So, I was building a game where it would be crucial to build. I found a script in a video and tried adapting it to my needs. So far I have made it be able to place, but I can't make it rotate. Whenever I click r(Rotate) it twitches and then comes back to it's original rotation. Sometimes it works but not really. I want it to rotate by 45º for now. Like I said, I found this in a video and don't really understand what is happening in this script. If anybody can do a little extra and explain how to make the virtual placing grid 1 stud by 1 stud.

Thanks!

And also, here is the script:

local Mouse = game.Players.LocalPlayer:GetMouse()
local Visual = workspace.TestModel
local Hitbox = Visual.Hitbox
 
 
--[[function RoundByThree(Number) // Original
    if math.floor(Number) == Number then
        if Number%3 == 0 then
            return Number
        elseif (Number - 1)%3 == 0 then
            return Number- 1
        elseif (Number + 1)%3 == 0 then
            return Number+ 1
        end
    end
    return Number
end]]

function RoundByThree(Number)
    if math.floor(Number) == Number then
        if Number%3 == 0 then
            return Number
        elseif (Number - 1)%1 == 0 then
            return Number
        elseif (Number + 1)%1 == 0 then
            return Number
        end
    end
    return Number
end

Mouse.Button1Down:connect(function()
	local newBlock = Hitbox:Clone()
	newBlock.Name = 'Wall'
	newBlock.Parent = workspace
	newBlock.CanCollide = true
	newBlock.Transparency = 0
end)

Mouse.KeyDown:connect(function(key)
	key:lower()
	if key == 'r' then
		Hitbox.Orientation = Hitbox.Orientation + Vector3.new(0, 90, 0)
	end
end)
   
local LastPosition = CFrame.new()
while true do      
    if Mouse.Target then
        if Mouse.Target.Name == "Base" then
            local TycoonBase = Mouse.Target
            local TycoonBaseSizeX, TycoonBaseSizeZ
            local HitboxSizeX, HitboxSizeZ
               
            TycoonBaseSizeX, TycoonBaseSizeZ = TycoonBase.Size.x, TycoonBase.Size.z

            HitboxSizeX, HitboxSizeZ = Hitbox.Size.x, Hitbox.Size.z
               
            local TycoonTopLeft = TycoonBase.CFrame * CFrame.new(Vector3.new(TycoonBase.Size.x/2, 0, TycoonBase.Size.z/2))
                           
			local RoundByThreeX = RoundByThree(math.floor(Mouse.Hit.p.x - TycoonTopLeft.x))
			local RoundByThreeZ = RoundByThree(math.floor(Mouse.Hit.p.z - TycoonTopLeft.z))
          
			if RoundByThreeX < -TycoonBaseSizeX + HitboxSizeX then
				RoundByThreeX = RoundByThreeX + HitboxSizeX
			end
			if RoundByThreeZ < -TycoonBaseSizeZ + HitboxSizeZ then
				RoundByThreeZ = RoundByThreeZ + HitboxSizeZ
			end
			local VectorComponent1 = CFrame.new(Vector3.new(TycoonTopLeft.x, Mouse.Target.Position.y, TycoonTopLeft.z))
			local VectorComponent2 = CFrame.new(Vector3.new(RoundByThreeX, Mouse.Target.Size.y/2, RoundByThreeZ))
			local VectorComponent3 = CFrame.new(Vector3.new(-HitboxSizeX/2, Hitbox.Size.y/2, -HitboxSizeZ/2))
			local NewVector = VectorComponent1*VectorComponent2*VectorComponent3
			local RegionVectorMin = NewVector * CFrame.new(Vector3.new(HitboxSizeX/2, -Hitbox.Size.y/2, HitboxSizeZ/2))
			local RegionVectorMax = NewVector * CFrame.new(-Vector3.new(HitboxSizeX / 2, -Hitbox.Size.y/2, HitboxSizeZ/2))
			local Hitboxes = game.Workspace:FindPartsInRegion3(
				Region3.new(
					Vector3.new(
						math.min(RegionVectorMin.x, RegionVectorMax.x),
						math.min(RegionVectorMin.y, RegionVectorMax.y),
						math.min(RegionVectorMin.z, RegionVectorMax.z)
					) + Vector3.new(0.1, 0, 0.1),
					Vector3.new(
						math.max(RegionVectorMin.x, RegionVectorMax.x),
						math.max(RegionVectorMin.y, RegionVectorMax.y),
						math.max(RegionVectorMin.z, RegionVectorMax.z)
					) - Vector3.new(0.1, 0, 0.1)
				), nil, 100
			)

			local ModelColliding = false
			for i, Hitbox in pairs(Hitboxes) do
				if Hitbox.Name == "Hitbox" and not Hitbox:IsDescendantOf(Visual) then
					ModelColliding = true
				end
            end

			if not ModelColliding then
					LastPosition = NewVector
			end
			Visual:SetPrimaryPartCFrame(LastPosition)
		end
    end
    wait()
end