Minecraft Block Placement Positioning Bug

I’ve got an annoying issue with a block controller system i’ve made. It’s referenced off minecraft and it’s supposed to correctly place blocks like minecraft, some times it does, some times.. just look at the picture below..

Why is that?, i’ll also place the code.


local BlockController = {}

local GameAssets: Folder = game:GetService("ReplicatedStorage"):WaitForChild("GameAssets")
local NotifController = require(GameAssets.MainAssets.ModuleScripts.Controller_Main:WaitForChild("Sub-Modules").NotifController)

BlockController.Initialize = function(tool)

	-- Declaring Variables
	
	local Player: Player = tool.Parent.Parent
	local PlayerMouse: Mouse = Player:GetMouse()
	local PlayerIsland: Folder = workspace.Islands:FindFirstChild(Player.UserId)

	local Character: Model = Player.Character or Player.CharacterAdded:Wait()
	local Humanoid: Humanoid = Character:WaitForChild("Humanoid")
	local RootPart: Part = Character.PrimaryPart

	local Connections: table = {}
	local CanUseTool: boolean = true

	local BlocksFolder: Folder = GameAssets.SideAssets.Props.Blocks

	-- CONFIG
	
	local MAX_RANGE = 20

	-- Connections [MAIN]
	
	Connections["ToolUsed"] = tool.Activated:Connect(function()
		if CanUseTool then
			CanUseTool = false

			local newPos: Vector3? = nil
			local Target = PlayerMouse.Target

			if Target then
				
				local BlocksFolder = PlayerIsland:FindFirstChild("IslandBody") and PlayerIsland.IslandBody:FindFirstChild("Blocks")
				
				if BlocksFolder and Target:IsDescendantOf(BlocksFolder) then
					
					local hitPos = PlayerMouse.Hit.Position
					local targetPos = Target.Position
					local offset = (hitPos - targetPos).Unit
					local roundedOffset = Vector3.new(
						math.sign(offset.X),
						math.sign(offset.Y),
						math.sign(offset.Z)
					)

					-- // Determine face direction
					
					if math.abs(offset.X) > math.abs(offset.Y) and math.abs(offset.X) > math.abs(offset.Z) then
						roundedOffset = Vector3.new(math.sign(offset.X), 0, 0)
					elseif math.abs(offset.Y) > math.abs(offset.X) and math.abs(offset.Y) > math.abs(offset.Z) then
						roundedOffset = Vector3.new(0, math.sign(offset.Y), 0)
					else
						roundedOffset = Vector3.new(0, 0, math.sign(offset.Z))
					end

					newPos = targetPos + roundedOffset * 4
				end
			end

			if newPos then
				
				local distance = (RootPart.Position - newPos).Magnitude
				
				if distance <= MAX_RANGE then
					
					GameAssets.SideAssets.Remotes.GlobalRemote:FireServer("PlaceBlock", tool.Name, newPos, tool:GetAttribute("ModelSupport"))
					
				else
					
					task.spawn(NotifController.NotifyPlayer, Player, ("Block is too far away (%.0f / %d studs)."):format(distance, MAX_RANGE))
					
					warn(("Cannot place block: too far away (%.0f / %d studs)."):format(distance, MAX_RANGE))
					
					CanUseTool = true
					
					return
						
				end
				
			else
				
				task.spawn(NotifController.NotifyPlayer, Player, "Could not place block, there was no valid target under your mouse.")
				
				warn("Could not place block: no valid target under mouse")
				
				CanUseTool = true
				
				return
			end

			GameAssets.SideAssets.Remotes.GlobalRemote:FireServer("DecrementUse", tool.Name)

			task.wait(0.25)


			if tool:GetAttribute("Uses") <= 0 then
				Humanoid:UnequipTools()

				if game:GetService("RunService"):IsClient() then
					GameAssets.SideAssets.Remotes.GlobalRemote:FireServer("DestroyTool", tool.Name)
				else
					tool:Destroy()
				end
			end

			CanUseTool = true
		end
	end)
end

return BlockController

When one block gets off the grid, then anything placed on that block will be off grid, but I dont think it can go from aligned with the grid to off the grid in the code you showed

So its probably with the placement system. Are they anchored? Are you using something like MoveTo which could interact with physics? Are the blocks extremely far away (could be floating point error)

And to fix you could round the position to the nearest cell which i think you can do with

-- repeat for every component of the vector (x,y,z)
-- where size is the size of one cube in the grid
math.round(num / size) * size
2 Likes