Chickynoid, server authoritative character replacement

Yeah its a concept applicable to any character controller really, If you want to look at how I did it, here is the function for checking for ledges itself, keep in mind this isn’t perfect, it has issues like being able to clip through roofs if specific things happen and more (I tried my best to account for all possible cases)

module.DetectionSettings = {
	LedgeCheckDistance = 4,
	LedgeCheckRange = 5,
	LedgeCheckOffset = Vector3.new(0,3,0),
	
	WallCheckOffset = Vector3.new(0,-0.001,0),
	WallCheckDistanceOffset = 0.001,
	
	VerifyCheckOffset = Vector3.new(0,1,0),
	
	GrabOffset = Vector3.new(0,-2,0),
	GrabDistance = 1,
}

function module.CheckLedge(simulation,cmd)
	-- Build raycast parameters
	local Whitelist = {}
	if Server then
		table.insert(Whitelist, Server.collisionRootFolder)
	else
		local CollisionRoot = Client:GetCollisionRoot()
		if CollisionRoot then
			table.insert(Whitelist, CollisionRoot)
		end
	end
	
	local Params = RaycastParams.new()
	Params.FilterType = Enum.RaycastFilterType.Whitelist
	Params.FilterDescendantsInstances = Whitelist
	
	-- Get
	local PlayerAngle = -MathUtils:PlayerAngleToVec(simulation.state.targetAngle)
	local LedgeCheckOrigin = (simulation.state.pos + PlayerAngle * module.DetectionSettings.LedgeCheckDistance)
		+ module.DetectionSettings.LedgeCheckOffset
	local LedgeDirection = MathUtils:AimPointToDir(LedgeCheckOrigin + Vector3.new(0,-1,0),LedgeCheckOrigin)
	
	-- Cast ray to find ledge near our look direction
	local LedgeResult = workspace:Raycast(LedgeCheckOrigin,LedgeDirection * module.DetectionSettings.LedgeCheckRange, Params)
	
	if LedgeResult then
		
		SeeQuery:Ray(true,LedgeCheckOrigin,LedgeResult,10).BrickColor = BrickColor.new("Lime green")
		
		local WallCheckOrigin = Vector3.new(simulation.state.pos.X,LedgeResult.Position.Y,simulation.state.pos.Z)
			+ module.DetectionSettings.WallCheckOffset
		local WallCheckTarget = LedgeResult.Position
			+ module.DetectionSettings.WallCheckOffset
		local WallCheckDirection = MathUtils:AimPointToDir(WallCheckTarget,WallCheckOrigin)
		local WallCheckDistance = (WallCheckOrigin - WallCheckTarget).Magnitude + module.DetectionSettings.WallCheckDistanceOffset
		local WallResult = workspace:Raycast(WallCheckOrigin, WallCheckDirection * WallCheckDistance, Params)
		
		if WallResult then
			
			SeeQuery:Ray(true,WallCheckOrigin,WallResult,10).BrickColor = BrickColor.new("Lime green")
			
			local VerifyCheckOrigin = WallCheckOrigin + module.DetectionSettings.VerifyCheckOffset
			local VerifyResult = workspace:Raycast(VerifyCheckOrigin,WallCheckDirection * WallCheckDistance,Params)
			
			if not VerifyResult then
				VerifyResult = SeeQuery:RecreateRayResult(VerifyCheckOrigin,WallCheckDistance,WallCheckDirection)
				SeeQuery:Ray(true,VerifyCheckOrigin,VerifyResult,10)
				
				-- return the result
				local pos = WallResult.Position
				local normal = WallResult.Normal

				return pos, normal
			else
				SeeQuery:Ray(true,VerifyCheckOrigin,VerifyResult,10).BrickColor = BrickColor.new("Lime green")
			end
		else
			WallResult = SeeQuery:RecreateRayResult(WallCheckOrigin,WallCheckDistance,WallCheckDirection)
			SeeQuery:Ray(true,WallCheckOrigin,WallResult,10)
		end
	else
		LedgeResult = SeeQuery:RecreateRayResult(LedgeCheckOrigin,module.DetectionSettings.LedgeCheckRange,LedgeDirection)
		SeeQuery:Ray(true,LedgeCheckOrigin,LedgeResult,10)
	end
	
end
7 Likes

I hope this receives some decent form of documentation in the future, whether by the creator or a third party. But in the meantime, I’m going to mess around with it.

6 Likes

Has anyone managed to support moving platforms with Chickynoid? I have taken a look at the source code and discovered that Chickynoid calculates collisions while being initialized, which prevents the collision of moving platforms from being updated.

I found a snippet of code that seems to imply that support is (or was) coming to “Dynamic” parts, which I assume means moving platforms.

if CollectionService:HasTag(instance, "Dynamic") then
    local record = {}
    record.instance = instance
    record.hull = self:GenerateConvexHullAccurate(instance, playerSize, instance.CFrame)
    record.currentCFrame = instance.CFrame

    -- Weird Selene shadowing bug here
    -- selene: allow(shadowing)
    function record:Update()
        if
            ((record.currentCFrame.Position - instance.CFrame.Position).magnitude < 0.00001)
            and (record.currentCFrame.LookVector:Dot(instance.CFrame.LookVector) > 0.999)
        then
            return
        end

        record.hull = module:GenerateConvexHullAccurate(instance, playerSize, instance.CFrame)
        record.currentCFrame = instance.CFrame
    end

    table.insert(module.dynamicRecords, record)

    return
end

I’m also interested in the usage of Chickynoid in non-humanoid use cases, such as a car or boat. I believe this is possible by simply changing the dimensions of the hitbox, but I’m not sure if it is as easy as that.

the max I’ve heard of was someone who made a fork to manually update the part collisions to the physics engine, and then re add the deleted code to work with moving platforms, but never tested it.

Excessive dynamic physical collisions lead to lag. What methods are there to solve it
Places that can be located
record.hull = Collision:GenerateConvexHullAccurate(instance, playerSize, instance.CFrame)

1 Like

I doubt this is gonna cause lag because its literally just a bounding box being calculated, also the new update said to be able to handle 100 players at a time with the improved server performance, and realisticly you are not gonna have 100 players in 1 server, specially in a Roblox server.
(even roblox servers struggle handling 100 players with having the work of physics handled to clients :rofl: )

Will there be a documentation on how to use this system? It may look very complex for not so experienced players. Like mods, collisions, mechanics, etc.

1 Like

Yes, a typical game does not require 100 players, but my game is Roguelike, which allows for a maximum of 100 enemies. However, I also want physical collisions between enemies, so I used dynamic physics. One of my enemies’ AI behaviors is to automatically follow the player’s current position, but as long as a large number of enemies approach each other and are not in a stationary state, the CPU usage and ping value will increase. Of course, canceling collisions between enemies will not result in any performance issues. But the game performance will be slightly worse,
I can only locate at the moment:record.hull = Collision:GenerateConvexHullAccurate(instance, playerSize, instance.CFrame)
1、Most enemies are in a stationary state

2、Players start moving, enemies automatically follow


Also, the player characters in the game have not been converted to Chickynoid,just enemy do this

Ah I see, you bring up a good point, player collisions are a thing that are deff missing from chickynoid now that I remember.

I asked because I don’t know how to use this, btw.
but I noticed testing on the demo place that it’s modular.

So? does someone have an idea of how do I use this serversided character system?

I don’t quite understand the Minkowski algorithm, so I can only slowly find a way to reduce the dynamic collisions calculations per frame on the server,If it really doesn’t work, I will have to consider maintaining dynamic collisions with up to 50 enemies

The dynamic hull used for player vs player collisions could be precalculated and reused.
Its doing way too much work here when it could be special cased.

You’re right, Chickynoid’s current dynamic collision is not suitable for a large number of units. If I still want to maintain dynamic collisions with multiple units, would you have any other suggestions? Thank you

its still doable, but you have to make it faster to update a hulls location.

The MinkowskiSum algorithm is still a bit difficult for me. I currently do not have the ability to improve the computational efficiency of dynamic hulls. Could you please provide a more efficient way? Thank you

1 Like

It’s so interesting, reducing 64 vertices to 8
image

I might be mistaken (please correct me if so), but the current implementation of Chickynoid is currently unusable for a production shooter game because bullet collision detection uses the box hitbox as seen on the server, which means bullets can damage someone without precisely hitting the character model.

It also prevents getting accurate information on where the bullet would hit a character at, which would prevent giving more damage to headshots and the like.

Snippet

if rayCastResult == nil then
    pos = origin + dir * range
else
    pos = rayCastResult.Position
    normal = rayCastResult.Normal
    hitInstance = rayCastResult.Instance

    --See if its a player
    local userId = rayCastResult.Instance:GetAttribute("player")
    if userId then
        otherPlayerRecord = server:GetPlayerByUserId(userId)
    end
end

The snippet above explains how Chickynoid handles bullet collision detection with players. However, it uses a raycast on the server side, which only has “box” parts in place of real character models.

I’m assuming the solution would involve some form of shapecasting, but I’m not sure how this would work if the bullet is only rendered on the client.

EDIT: I just remembered that there has been a shooter that used Chickynoid in production (Rift Royale). I guess I didn’t read enough of the source code, which is on me. Still, I’m interested in figuring out how projectile detection works with character hitboxes, espically since the server only renders boxes, and the projectiles are simulated on the server…

to answer your question, no chickynoid doesn’t has a way to use the model for limb damage or headshots or anything like that, Rift Royale did had it but the current version of chickynoid even states as a “Todo” for that kind of stuff.

So yeah its only the hitbox for now :(, also make sure to use antilag for the lag compensation when registering hits.

Does this prevent administrative commands such as Adonis’ :fly command from working?