How would I make this script into a grid placement system?

Hello, So I got a placement system and I need help to make it a grid placement system I have tried a lot of way but all failing.
the gird needs to be 4,4,4 any help is really wanted.
Local script

local placementEvent = game.ReplicatedStorage.PlacementEvent
local ObjectFolder = game.ReplicatedStorage:WaitForChild("ObjectFolder")

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local mouse = player:GetMouse()

local Frame = script.Parent:WaitForChild("Frame")
local UserImputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local PlacingObject = false
local RotatingObject = false
local RotatingObjectCoolDown = false 

for i, Button in pairs(Frame:GetChildren()) do
	
	if Button:IsA("TextButton") then
		
		Button.MouseButton1Click:Connect(function()
			
			if PlacingObject == false then
				
				PlacingObject = true
				Frame.Visible = false
				
				local RotatingAmount = 0
				
				local PrevieuwObject = ObjectFolder:FindFirstChild(Button.Name):Clone()
				PrevieuwObject.Parent = game.Workspace
				
				for i, Parts in pairs(PrevieuwObject:GetDescendants()) do
					
					if Parts:IsA("BasePart") then
						
						Parts.Transparency = 0.5
						Parts.CanCollide = false						
					end
				end
				
				UserImputService.InputBegan:Connect(function(Key, GameProcessed)
					
					if not GameProcessed then
						if not RotatingObjectCoolDown then
							if Key.KeyCode == Enum.KeyCode.R then

								RotatingObject = true

								while RotatingObject == true do
									wait()
									RotatingAmount += 90
									RotatingObjectCoolDown = true
									wait(0.1)
									RotatingObjectCoolDown = false
								end							
							end
						end						
					end					
				end)
				
				UserImputService.InputEnded:Connect(function(Key)
					
					if Key.KeyCode == Enum.KeyCode.R then
						
						RotatingObject = false
					end
				end)
				
				RunService.RenderStepped:Connect(function()
					
					if PlacingObject == true then
						
						mouse.TargetFilter = PrevieuwObject
						
						if PrevieuwObject:FindFirstChild("MainPart") then
							
							local ObjectCFrame = CFrame.new(mouse.Hit.Position.X, mouse.Hit.Position.Y + PrevieuwObject.PrimaryPart.Size.Y / 2, mouse.Hit.Position.Z)
							local ObjectAngles = CFrame.Angles(0, math.rad(RotatingAmount), 0)
							
							PrevieuwObject:SetPrimaryPartCFrame(ObjectCFrame * ObjectAngles)
						end
					end			
				end)
				
				mouse.Button1Up:Connect(function()
					
					if PlacingObject == true then
						
						PlacingObject = false
						
						placementEvent:FireServer(PrevieuwObject.Name, PrevieuwObject.PrimaryPart.CFrame)
						
						Frame.Visible = true
						PrevieuwObject:Destroy()
					end
				end)	
			end		
		end)	
	end	
end

Server script

local PlacementEvent = game.ReplicatedStorage.PlacementEvent
local ObjectFolder = game.ReplicatedStorage:WaitForChild("ObjectFolder")

PlacementEvent.OnServerEvent:Connect(function(Player, PreviewObject, ObjectCFrame)
	
	local Object = ObjectFolder:FindFirstChild(PreviewObject):Clone()
	
	Object:SetPrimaryPartCFrame(ObjectCFrame)
	Object.Parent = game.Workspace
end)

Generally speaking you can make a grid system by taking your coordinates, dividing them then multiplying them back like so. math.floor is important to remove decimal places or else you will end up with the same number.

local grid_x = math.floor(object.x / 4) * 4
local grid_y = math.floor(object.y / 4) * 4
local grid_z = math.floor(object.z / 4) * 4

local new_position = Vector3.new(grid_x, grid_y, grid_z)

I tried applying this to my script but I cant seem to get it to work.
Do you know how to apply this the right way?

try this :slight_smile:

local x = math.floor(mouse.Hit.Position.X / 4) * 4
-- y probably does not need to be on-grid
local y = mouse.Hit.Position.Y + PrevieuwObject.PrimaryPart.Size.Y / 2
local z = math.floor(mouse.Hit.Position.Z / 4) * 4
local ObjectCFrame = CFrame.new(x, y, z)

Where would I add this in my script?

In your renderstepped connection, where you normally define ObjectCFrame

It works but I am having the problem that if I try place a block Going up or down on a item and on the basepart the block isn’t going to grid and on some of my block options there going on a grid but 2 studs away from the map grid.
Capture
The flat square is to grid but the block is of grid.

Also how would I make it that you can’t lace a block where a block already is?
I got tis problem.
2
I think it would be cool that when the player tries to place a block where a block already is that the prieview block turns red and when the move it away it goes back to green.