Chickynoid, server authoritative character replacement

Hello, Chickynoid. Today I found your resource, and after reading all (not all but a lot of) replies, I tried to join your test place. And I got some questions, about is behavior I got intented?

  1. At first, character jump height is very random. Sometimes I jump by 3 studs, sometimes by 15
  2. When theres lag spikes, character teleports further than he able to move (Unable to record video here bc lag spikes aren’t guaranteed to appear =(
  3. Roblox default system allows player to move mid-air, when jumping for example. But when I tried, I got either delays or complete inability to change move direction, only character rotated.

Must say that NONE of NPCs had such weird behavior.

1 Like

1 Holding jump button makes you jump higher (jump thrust constant)
2 This is because the server has all control of the character, and keeps running your inputs, and you get resynced.
3 Edit the constants on the NicerHumanoid mod to adjust the movement to your needs.

1 Like

I noticed that constants are sent now every frame if I am not incorrect, if so is there a built in way to not replicate these every frame?, they make my packets be too big for unreliable events.

What ways could I do to solve the problem with packets being too big (asides from just reducing size which i am already working on)

1 Like

Ah, they’re not sent every frame but if you get every packet rejected for being too big, the delta compression will never kick in.
Ill add a patch, but in the meantime send big playerstates by reliables.

1 Like

also, even if they are not sent every frame, I still kind of liked that the cosntants are sent, I noticed that now when I only change it from the server, the client automatically syncs because it gets replicated to it in some way, which is nice for certain scenarios.

Ill also reduce the amount of data I’m sending on the first place too, I just noticed I’m sending too much unnecessary data.

They should be removed by delta compression on subsequent frames unless they change.

1 Like

Is there documentation here? Or is it planned? The amount of setup and actions required with this system is insane to deal with simply by reading the source code

1 Like

unfortunately, that’s just how it is, you must torture yourself for weeks to figure out how to use it somewhat properly, but once you do get the hang of it, it’s actually very cool.

1 Like

I mean, I see you work a lot with it, What are the main modules generally used for characters and players?

The main things I would say I use to program stuff related to movement are the mods inside the characters folder inside utils, you can write and attach behavior to the “Simulation” object, as long as your code is deterministic it will automatically sync the Simulation.state with the client and server.

I cant really explain much since theres too much stuff to cover, However I can say I really like chickynoid, I don’t think it’s for everyone because of it’s limitations at the moment, but not only does it stops cheats but helps with solving issues with latency, i really like how you can rewind hitboxes to do server sided hit reg with no issues.

the most confusing part about it is the style it’s written in; it really feels like C#

2 Likes

Edited

Angles seem to work backwards now for some reason, was this intended?, I thought it was the new PlayerAngleToVec function messing it up, but after trying to also use the old one, it returns the same result.

My ladder detection now just works backwards, I am not sure if this was intended.

image

I wrote a fixed update module a while back and just implemented it into Chickynoid (to replace heartbeat). It seems to work perfectly but I would appreciate a second opinion to validate it.

Link to place with said changes

1 Like

Im pretty sure you can already do that by changing the server module settings, if im not incorrect by default its 20 tps

hmmm, I guess it does have it built in already (my bad not familiar with chickynoid v2 at all).

although with my solution it forces the physics to use a fixed timestep regardless of framerate, which should make physics more consistent since they aren’t using a changing deltaTime (will have to do more testing).

2 Likes

I really don’t understand why would you want a fixed delta time, its probably going to mess with the way chickynoid syncs with the server, and also the lower the server tps is, the worse the physics result is gonna be, as not always will it be able to keep up with updating in a fixed way.

A fixed time step is incredibly important for deterministic physics, the imprecision/randomness of a changing deltaTime is usually the cause of physics inconsistencies.

3 Likes

Ledge detection and ladder detection on chickynoid!
image

might release this as an open source mod thingy.

7 Likes

This ledge detection image gave me understanding about how it even works. Thanks! (detection itself, not chickynoid)

1 Like

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