my part spwans inside the ground when i use my building system
client :
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local RE = ReplicatedStorage.RemoteFunction
local Buildings = ReplicatedStorage.Buildings
local Stuff = workspace.Stuff
local plr = Players.LocalPlayer
local mouse = plr:GetMouse()
local building = false
local currentModel = nil
local canPlace = nil
local debounce = false
local rotationY = 0 -- Track Y-axis rotation
local ROTATION_INCREMENT = 15 -- Rotation step in degrees
local function updateModelPosition()
if not building or not currentModel then return end
local mouseRay = mouse.UnitRay
local castRay = Ray.new(mouseRay.Origin, mouseRay.Direction * 1000)
local ignoreList = {plr.Character, currentModel}
local hit, position = workspace:FindPartOnRayWithIgnoreList(castRay, ignoreList, true, true)
if hit and (hit:IsA("BasePart") or hit:IsA("Terrain")) then
canPlace = true
for _, part in pairs(currentModel:GetDescendants()) do
if part:IsA("BasePart") then
part.BrickColor = BrickColor.new("Bright blue")
end
end
-- Adjust height based on model bounding box
local modelHeight = currentModel:GetExtentsSize().Y / 2
position = Vector3.new(position.X, position.Y + modelHeight, position.Z)
else
canPlace = false
for _, part in pairs(currentModel:GetDescendants()) do
if part:IsA("BasePart") then
part.BrickColor = BrickColor.new("Bright red")
end
end
end
-- Apply rotation and position
local rotation = CFrame.Angles(0, math.rad(rotationY), 0)
local newCFrame = CFrame.new(position)
currentModel:SetPrimaryPartCFrame(newCFrame * rotation)
end
local function startBuilding(model)
if building then return end
if not model or not model:IsA("Model") then
warn("Invalid model passed to startBuilding!")
return
end
building = true
currentModel = model:Clone()
if not currentModel.Name then
warn("Model does not have a valid Name!")
return
end
currentModel.Parent = Stuff
currentModel.PrimaryPart = currentModel:FindFirstChild("PrimaryPart") or currentModel:FindFirstChildWhichIsA("BasePart")
currentModel:SetPrimaryPartCFrame(plr.Character.HumanoidRootPart.CFrame)
currentModel.PrimaryPart.CanCollide = false
for _, part in pairs(currentModel:GetDescendants()) do
if part:IsA("BasePart") then
part.Material = Enum.Material.Neon
part.Transparency = 0.5
end
end
rotationY = 0 -- Reset rotation
if not updateConnection then
updateConnection = RunService.RenderStepped:Connect(updateModelPosition)
end
end
local function stopBuilding()
if not building or debounce then return end
if currentModel and canPlace then
if not currentModel.Name then
warn("currentModel does not have a valid Name!")
return
end
debounce = true
local modelCFrame = currentModel.PrimaryPart.CFrame
-- Ensure we are passing the model's Name
RE:InvokeServer(currentModel.Name, modelCFrame)
currentModel:Destroy()
currentModel = nil
building = false
debounce = false
if updateConnection then
updateConnection:Disconnect()
updateConnection = nil
end
end
end
UserInputService.InputBegan:Connect(function(input, gameProcessed)
if gameProcessed then return end
if input.KeyCode == Enum.KeyCode.R then
rotationY = rotationY + ROTATION_INCREMENT
elseif input.KeyCode == Enum.KeyCode.T then
rotationY = rotationY - ROTATION_INCREMENT
end
if input.UserInputType == Enum.UserInputType.MouseButton1 and building then
stopBuilding()
end
end)
for _, button in pairs(script.Parent:GetChildren()) do
if button:IsA("ImageButton") then
button.MouseButton1Click:Connect(function()
if not building then
local modelName = button.Value.Value.Name
local model = Buildings:FindFirstChild(modelName)
if model then
startBuilding(model)
end
end
end)
end
end
serverside :
RE.OnServerInvoke = function(player, modelName, cframe)
print("Received modelName:", modelName, "with CFrame:", cframe)
if not modelName or typeof(modelName) ~= "string" then
warn("Invalid modelName received!")
return
end
local model = Buildings:FindFirstChild(modelName)
if not model then
warn("Model not found in Buildings:", modelName)
return
end
local newModel = model:Clone()
newModel.PrimaryPart = newModel.PrimaryPart or newModel:FindFirstChildWhichIsA("BasePart")
if not newModel.PrimaryPart then
warn("No PrimaryPart found for model:", modelName)
return
end
-- Perform a downward raycast to find the exact ground position
local rayOrigin = cframe.Position
local rayDirection = Vector3.new(0, -1000, 0) -- Cast ray down 1000 studs
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {workspace.Stuff, newModel}
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
local result = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
if result then
-- Use the surface's Y-position for proper placement
local surfaceY = result.Position.Y
local modelHeight = newModel:GetExtentsSize().Y / 2
local adjustedCFrame = CFrame.new(cframe.Position.X, surfaceY + modelHeight, cframe.Position.Z)
newModel:SetPrimaryPartCFrame(adjustedCFrame)
newModel.Parent = workspace.Stuff
-- Anchor parts after placing
RunService.Heartbeat:Wait()
for _, part in pairs(newModel:GetDescendants()) do
if part:IsA("BasePart") then
part.Anchored = true
end
end
saveBlockData(player, modelName, adjustedCFrame) -- Save the corrected CFrame
else
warn("No surface found below the placement position!")
return
end
end