Chickynoid, server authoritative character replacement

I have rewritten the collision module to use block casting; after lots of tweaking, I’ve gotten it to a state where I can no longer clip into objects, and there are no mispredicts! It is pretty simple, but it took me forever to think of it. Now, we can use variable-sized hitboxes!

This would probably get better results with capsule colliders, but its been working fine for me with the block ones.

It is a drop in replacement, the only bit of code that needs changing is the ProjectVelocity function in the Simulation module.

        if planes[result.normal] == nil then
			planes[result.normal] = true

            --Deflect the velocity and keep going
            moveVel = MathUtils:ClipVelocity(moveVel, result.normal, 1.0)
        else
            --We hit the same plane twice, push off it a bit
            movePos += result.normal * 0.01
            moveVel += result.normal
            break
        end

I changed it to use the results normal instead of its plane number.

local RunService = game:GetService("RunService")
local CollectionService = game:GetService("CollectionService")
local Debris = game:GetService("Debris")
local PhysicsService = game:GetService("PhysicsService")

if RunService:IsServer() then -- probably just create these in studio beforehand or the server module instead of here
	PhysicsService:RegisterCollisionGroup("GameArea")
	PhysicsService:CollisionGroupSetCollidable("GameArea","GameArea",true)
	PhysicsService:CollisionGroupSetCollidable("GameArea","Default",false)
end


local module = {}

-- Constants
local DEFAULT_SIZE = Vector3.new(3, 5, 3)
local SHIFTBACK = 1 -- shift start position of the cast back by a constant offset, in opposite direction of movement. this will avoid the cast ever starting too close to a wall and us phasing through. There are some quirks when going over small terrain or features.
-- under 1 there are some rare cases when at extreme angles that you can get close enough to a wall to phase through it

function module:Sweep(startPos, endPos) -- not sure how to properly impelement all solid and start solid, possibly do a getpartBoundsInBox check at the starting position, but that will pick up meshparts incorrectly
	local data = {
		startPos = startPos,
		endPos = endPos,
		fraction = 1,
		startSolid = false,
		allSolid = false,
		normal = Vector3.new(0, 1, 0),
	}
	
	
	local offset = endPos-startPos
	local distance = offset.Magnitude
	
	if distance <= 0 or distance >= 1024 then
		return data
	end
	
	local direction = offset.Unit
	
	local params = RaycastParams.new()
	params.CollisionGroup = "GameArea"
	--params.FilterType = Enum.RaycastFilterType.Exclude
	--params.FilterDescendantsInstances = {}


	local castOrigin = startPos-(direction*SHIFTBACK)
	

	local result = workspace:Blockcast(
		CFrame.new(castOrigin),
		DEFAULT_SIZE,
		direction*(distance+SHIFTBACK),
		params
	)


	if result then

		data.fraction = (result.Distance-SHIFTBACK) / direction.Magnitude
		data.normal = result.Normal
		data.endPos = castOrigin + direction.Unit * result.Distance
		--data.allSolid = data.startSolid and data.fraction < 0.001
	else
		data.endPos = endPos
	end

	return data
end


function module:MakeWorld(folder)
	debug.setmemorycategory("Collision")

	-- Process existing parts
	for _, instance in ipairs(folder:GetDescendants()) do
		if instance:IsA("BasePart") and instance.CanCollide then
			instance.CollisionGroup = "GameArea"
		end
	end

	-- Handle new parts
	folder.DescendantAdded:Connect(function(instance)
		if instance:IsA("BasePart") and instance.CanCollide then
			instance.CollisionGroup = "GameArea"
		end
	end)

end


return module

As stated previously by MrChickenRocket, there are some mispredicts on rotated base parts due to how Roblox replicates them with slight inaccuracies. We can’t account for that in the collision detection now, so it may be necessary to round them on the client and server at runtime or manually replicate the accurate CFrames.