So basically, I have a placement system. The first time I place something down, it places it once. Then, when I place something again, it places it two times, and so on.
Local Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PlaceStructure = ReplicatedStorage:WaitForChild("PlaceStrucutre")
local Structures = ReplicatedStorage:WaitForChild("Structures")
local UIS = game:GetService('UserInputService')
local RunService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local StructureFrame = script.Parent.ScrollingFrame
local char = player.Character or player.Character:Wait()
local HumanoidRootPart = char:WaitForChild("HumanoidRootPart")
local mouse = player:GetMouse()
local yBuildingOffset = 5
local maxPlacingDistance = 50
local rKeyIsPressed = false
local placingStructure = false
for _, structureButtons in pairs(StructureFrame:GetChildren()) do
if structureButtons:IsA("TextButton") then
structureButtons.MouseButton1Click:Connect(function()
StructureFrame.Visible = false
local yOrientation = 0
local goodToPlace = false
local placedStructure
if placingStructure == false then
placingStructure = true
local clientStructure = Structures:FindFirstChild(structureButtons.Name):Clone()
clientStructure.BrickColor = BrickColor.new("Forest green")
clientStructure.Material = "Neon"
clientStructure.CanCollide = false
clientStructure.Parent = game.Workspace
local startingCFrame = CFrame.new(0, -2, -15)
clientStructure.CFrame = HumanoidRootPart.CFrame:ToWorldSpace(startingCFrame)
RunService.RenderStepped:Connect(function()
local mouseRay = mouse.UnitRay
local castRay = Ray.new(mouseRay.Origin, mouseRay.Direction * 1000)
local ignoreList = {clientStructure, char}
local hit, position = workspace:FindPartOnRayWithIgnoreList(castRay, ignoreList)
if hit and (HumanoidRootPart.Position - clientStructure.Position).Magnitude < maxPlacingDistance then
goodToPlace = true
clientStructure.BrickColor = BrickColor.new("Forest green")
else
goodToPlace = false
clientStructure.BrickColor = BrickColor.new("Crimson")
end
local newAnglesCFrame = CFrame.Angles(0, math.rad(yOrientation), 0)
local newCFrame = CFrame.new(position.X, position.Y + yBuildingOffset, position.Z)
clientStructure.CFrame = newCFrame * newAnglesCFrame
end)
UIS.InputBegan:Connect(function(input)
if input.KeyCode == Enum.KeyCode.R then
rKeyIsPressed = true
local rotationSpeed = 5
while rKeyIsPressed do
wait()
if placingStructure == true then
yOrientation = yOrientation + rotationSpeed
end
end
end
end)
UIS.InputEnded:Connect(function(input)
if input.KeyCode == Enum.KeyCode.R then
rKeyIsPressed = false
end
end)
UIS.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
if placingStructure == true then
if goodToPlace == true then
local StructureCFrame = clientStructure.CFrame
placedStructure = PlaceStructure:InvokeServer(clientStructure.Name, StructureCFrame)
if placedStructure == true then
placingStructure = false
clientStructure:Destroy()
StructureFrame.Visible = true
end
end
end
end
end)
end
end)
end
end
Server Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PlaceStructure = ReplicatedStorage:WaitForChild("PlaceStrucutre")
local Strucutres = ReplicatedStorage:WaitForChild("Structures")
PlaceStructure.OnServerInvoke = function(player, StrucutreName, StructureCFrame)
local crafted
local realStructure = Strucutres:FindFirstChild(StrucutreName):Clone()
if realStructure then
realStructure.CFrame = StructureCFrame
realStructure.Parent = game.Workspace
crafted = true
else
crafted = false
end
return crafted
end
It’s possible that the behavior is related to the name of the part being placed. If the part name is not unique, it’s possible that the code that checks if a part already exists in the workspace may be incorrectly identifying the part as not yet placed, causing it to place multiple times.
I would recommend double-checking the names of the parts being placed to ensure that they are unique and not conflicting with any existing parts in the workspace. Additionally, you can add debug prints to the code to see if the part is being identified as already existing in the workspace when it is being placed multiple times.
It looks like you have a functional placement system that allows the player to place structures in the game world. The system is activated when the player clicks on a structure button in the GUI, and a green preview structure is placed in the world. The player can then use the mouse to position and rotate the preview structure, and press the “R” key to rotate it around the y-axis.
When the player clicks the left mouse button, the system sends a request to the server to place the structure. The server script then finds the real structure model in ReplicatedStorage, clones it, and sets its position and orientation to match the preview structure. If successful, the real structure is parented to the game world and the preview structure is destroyed.
Overall, your placement system seems to be working well. If you have any specific questions or issues, feel free to ask!
If I’m seeing this right, you are adding a MouseButton1Click listener function to the TextButtons in your StructureFrame. In that MouseButton1Click function, you are creating a connection to UIS:InputBegan that will actually fire the server. However, you never disconnect that function. So every time the TextButton is clicked, it is creating another connection to UIS:InputBegan. Therefore, the first time you click the TextButton, it creates that connection and fires the server to place a building. The second time you click, you make a new connection and are now placing two buildings because the first connection still exists. Third time, there are now three connections, and so on and so on. I think you can avoid duplicates by creating a variable first, then setting that listener to the variable, and then calling :Disconnect() on the variable after the server is fired. I reread that a couple times over and I think I explained what I’m thinking there…hopefully