i have this module right here which is responsible for calculating its block cframe for both client and the server, the problem is that half of the block is submerged (or whatever its called)
i tried adding the primary part y size to the cframe but it has a somewhat glitchy behavior
-- [[ SERVICES ]]
local ReplicatedStorage = game:GetService('ReplicatedStorage')
local UserInputService = game:GetService('UserInputService')
local RunService = game:GetService('RunService')
local Players = game:GetService('Players')
-- [[ MATH FUNCTIONS ]]
local floor = math.floor
local round = math.round
-- [[ MODULE ]]
local Placement = {
constants = {
GRID_UNIT = 3;
MATRICES = {
BACK = Vector3.new(0, -1, 0);
TOP = Vector3.new(0, 0, -1);
RIGHT = Vector3.new(-1, 0, 0);
};
}
}
table.freeze(Placement.constants)
function Placement.new(canvas: BasePart)
local self = setmetatable({}, {__index = Placement})
self.canvas = canvas;
return self
end
function Placement:Raycast(mouse: Mouse, params: RaycastParams?)
local unitRay = mouse.UnitRay
return workspace:Raycast(unitRay.Origin, unitRay.Direction * 1000, params)
end
function Placement:Snap(pos: Vector3): Vector3
return Vector3.new(
round(pos.X / self.constants.GRID_UNIT) * self.constants.GRID_UNIT,
round(pos.Y / self.constants.GRID_UNIT) * self.constants.GRID_UNIT,
round(pos.Z / self.constants.GRID_UNIT) * self.constants.GRID_UNIT
)
end
function Placement:GetCFrame(model: Model, position: Vector3, normal: Vector3)
return CFrame.new(
self:Snap(position + normal)
)
end
function Placement:Colliding(model: Model, plot: Instance)
local params = OverlapParams.new()
params.FilterDescendantsInstances = {plot}
params.FilterType = Enum.RaycastFilterType.Whitelist
local parts = workspace:GetPartsInPart(model.PrimaryPart, params)
for _, part in parts do
if not model:IsAncestorOf(part) then
return true
end
end
end
function Placement:Place(...)
return ReplicatedStorage.Remotes.Place:InvokeServer(...)
end
return Placement
baseplate properties: