Chickynoid, server authoritative character replacement

also thats odd why wouldnt it use inputs, it sounds much safer and framerate wouldnt affect it if you use delta time, not like i know much about server authoritative movement yet, so maybe im just being stupid by saying this.

It does use inputs for commands

1 Like

that was a quick reply, anyways happy new year hope everyone is having fun right now.

I’ll probably consider using this (if i get it and player choice rigs (user deciding r6/r15) working) on games where movement isn’t a major factor, I wouldn’t suggest using server-authorative physics things in any game with many players and/or intensive movement, or if you just expect players to have terrible connections regardless.

Oh dont worry about the connection issues it runs fine, in fact its so good at handling bad pings that intense “pull” rollbacks almost never happen.

Will this support terrain water?

Also following to this I finally understood what MrChickenRocket was trying to tell me.

He meant predicting if we were gonna keep charging not when we were gonna charge

I have taken a look more indepth into various things inside chickynoid I stumbled into Projectile Sniper module script and while im still extremely confused about commands I think ill eventually get the hang of it, So far I know you can use the bitbuffer module to compress the packets from what I saw and send them over via commands although while checking the generate command module I saw that you need to hardcode commands which is a bit inconvinient but it works I guess.

I also discovered another solution that could be implemented using the antilag module inside chickynoid for compensating charge mechanics based on these diagrams, I will keep reading more how chickynoid does its cooldowns and more to learn if this is the correct solution or not.

image

2 Likes

Following to this heres the thing im working on for chickynoid

So I was like trying to implement “Commands” for chickynoid for my game actions (Blocking,Jabing,Charging,Shoving, etc.)

So after like 1 week of trying my hardest to understand chickynoid’s innerworkings I found out how commands tick!

Commands are part of the “GenerateCommand” mod, these are by deffault sent every frame chickynoid takes to the server and will get the inputs on that momment.

Problem is they are hardcoded and hard to add as :GenerateCommand() function is responsable for generating the final command sent to the server which is later picked up by :Heartbeat() and passed to the server, So theres really not an easy way to add your own commands to be sent to the server witjout forking and tampering with chickynoid

So I made this modiffication which I think works fine, right now im focussing on constructing commands, ill later focuss on Processing commands on the client so they also run client actions before they are sent to the server just how the :ProcessCommand() function does.

The moddification goes inside Heartbeat and the reason for that is uhh I dont actually have a reason i think it would have been better inside :GenerateCommand() but I forgot why

Heres part of the module that makes the commands get attached to the main command and also handles OOP creation of commands

This is pretty barebones and its missing stuff like the ProcessServerCommand function which takes charge of receieving the commands on the server checking what they have and running the respected functions assigned to these commands so they can run the server code for whatever we need.

Anyways that was my cool uhh project that im working on, If anyone knows a better way to do what I am doing feel free to tell me im just a dumb person trying to make a game with chickynoid!

1 Like

You didn’t need to do that, these lines already allow you to add onto the command.
image

2 Likes

You are kidding me right, sigh I really am an idiot adding things that were already made

There goes my afternoon :pensive:

How could I have missed that IT WAS LITERALLY THERE!

Anyways thank you for showing me how it was actually made.

2 Likes

I think I am no longer an idiot and did it right this time! :smile:

wrote this simple mod which basicly allows you to add data to a table which then is sent as commands, the reason for this is because I want any script to at any point be able to create commands and be able to also remove commands

For example I have an OOP tool/inventory system, I make a class for it called melee, as soon as the equip function for my system is called on the client, we create the actions for the things we can perform (Block,Charge,Hit,Shove,Inspect) which starts sending commands to the server with the states of said actions. When we are done using our melee and we unequip it we can get rid of these actions so we stop wasting bandwith sending useless data to the server.

I guess ill test how this thing i made works and try to use the bitbuffer module for data that cannot be predicted, as for the input data to the server ill use something similar like enums just how MrChickenRocket did it that way the server already knows what the numbers sent mean.

3 Likes

Working on something big for chickynoid that I plan to release to the public which will facilitate a lot the developement for games on chickynoid.

Its Custom Tools for chickynoid, Chickynoid does not support roblox tools for obvious reasons, so I am writing a mod called InventoryMod, which allows chickynoids to have custom inventories that can hold different objects, It also already comes bundled with an object class called CTool (CitrusTool).

Citrus Tools imitate as much as possible the behavior of roblox tools via chickynoid and are split into different components to make its modification as easy as possible so you can adjust them to work into your game, I also plan to make them work instead of via input events via using a :ProcessCommand() function locally and on ServerSide so they work similar to the already existing weapons mod, and they also support rollback functions the user can code in, In case whatever you are coding desyncs from the server or needs to be controlled from the server, Such as unequipping an users tool.

Heres the way the Client sided components are built, keep in mind they are a rewrite of an older system I made so rn im just kinda rebuilding it and then modifying to work with chickynoid, Networking has not been done yet because I need to add a lot of things.

image

ClientInventoryMod

local module = {}
module.Objects = {}
module.InventoryRecords = {}

function module:Setup(client)
	-- Get all of our different Objects
	for i,v in pairs(script:GetChildren()) do
		if v:IsA("ModuleScript") then
			-- Setup and add our objects to the module's table
			local Contents = require(v)
			Contents:Setup()
			self.Objects[v.Name] = v
		end
	end
end

function module:Step(client, _deltaTime)
end

return module

CTool

-- Custom tools (CTool) mod!
local CTool = {}
-- Services
local Players = game:GetService("Players")
local StarterGui = game:GetService("StarterGui")
local ReplicatedFirst = game:GetService("ReplicatedFirst")

local LocalPlayer = Players.LocalPlayer
local FastSignal = require(ReplicatedFirst.Packages.Chickynoid.Vendor.FastSignal)

CTool.__index = CTool

CTool.ClassName = "CTool"
CTool.Classes = {}
CTool.IsSetup = false
CTool.ToolIDCounter = 0
CTool.InventoryRecords = {}
CTool.InventoryRecords.Server = {}
-- Events
CTool.OnCToolOwnershipToLocalPlayer = FastSignal.new()
CTool.OnCToolRemovedFromLocalPlayer = FastSignal.new()
CTool.OnCToolEquipped = FastSignal.new()
CTool.OnCToolUnequipped = FastSignal.new()
-- Client Only thing
CTool.InputHandler = nil

-- Constructor function for CTool Object
function CTool.new()
	local self = setmetatable({
		ID = CTool.ToolIDCounter,
		Owner = nil,
		IsEquipped = false,
		ClassName = CTool.ClassName,
		Origin = "Client",
		-- Change this when making a new class
		CToolClass = CTool.ClassName,
	}, CTool)
	-- Store our Object inside the Records so we can find it
	CTool.InventoryRecords[self.ID] = self
	-- Update the ID counter
	CTool.InventoryRecords += 1
	
	return self
end
-- Sets a CTool's Owner to the given Player
function CTool:SetOwner(Player)
	
	if CTool.InventoryRecords[Player.UserId] then
		self.Owner = Player
		CTool.InventoryRecords[Player.UserId].Backpack[self.ID] = self
		-- Run exclusive code to the Local Player
		if Player == LocalPlayer then
			CTool.OnCToolOwnershipToLocalPlayer:Fire(self)
		end
	else
		warn("Inventory not found")
	end
end
-- Unequips tool and runs class code
function CTool:Unequip()
	if self.IsEquipped == true then
		local Inventory = CTool.InventoryRecord[self.Owner.UserId]
		local ClassFunctions = require(script[self.ClassName])
		-- run it's class code
		self:UnequipClass()
		self.IsEquipped = false
		Inventory.Hand = nil
		-- Fire the local events for the input handler
		CTool.OnCToolUnequipped:Fire(self)
	end
end
-- Equip tool and runs class code
function CTool:Equip()

	if self.IsEquipped == false then

		local Inventory = CTool.InventoryRecord[self.Owner.UserId]

		local ClassFunctions = require(script[self.ClassName])
		-- Check if tool is already equipped and unequip if so
		if Inventory.Hand then
			Inventory.Hand:Unequip()
		end
		self:EquipClass()
		self.IsEquipped = true
		Inventory.Hand = self
		-- Fire the local events for the input handler
		CTool.OnCToolEquipped:Fire(self)
	end
end
-- Removes all traces of CTool object
function CTool:Destroy()
	-- Check if it has an owner to remove it from backpack and hand
	if self.Owner then
		local Inventory = CTool.InventoryRecords[self.Owner.UserId]

		if self.IsEquipped == true then
			self:Unequip()
		end
		
		Inventory.Backpack[self.ID] = nil
	end
	-- Fire local events for the input handler
	CTool.OnCToolRemovedFromLocalPlayer:Fire(self)
	self = nil
	return self
end
-- Sets up all the necesary code to make the object class fully work
function CTool:Setup()
	print("RAN")
	if CTool.IsSetup == false then
		-- Hide roblox's deffault inventory Gui
		StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)
		
		-- Setup all other Classes of CTool
		for i,v in pairs(script:GetChildren()) do
			if v:IsA("ModuleScript") then
				local Class = require(v)
				Class:Setup()
				-- Detect if this is the Module in charge of controlling CTools, if it is then its not a class
				if Class.InputHandler then
					CTool.InputHandler = Class
				else
					print(v.Name)
					CTool.Classes[Class.ClassName] = Class
				end
			end
		end
	end
end

return CTool

InputHandler component

local InputHandler = {}
-- Services
local ContextActionService = game:GetService("ContextActionService")
local Players = game:GetService("Players")

local CTool = require(script.Parent)

local LocalPlayer = Players.LocalPlayer
InputHandler.InputHandler = true
-- idk load things
InputHandler.Assets = script.Assets

InputHandler.Hotbar = {}
InputHandler.HotbarSlotsInUse = 0
-- Settings
InputHandler.Settings = {}
InputHandler.Settings.Keybinds = {
	[1] = Enum.KeyCode.One,
	[2] = Enum.KeyCode.Two,
	[3] = Enum.KeyCode.Three,
	[4] = Enum.KeyCode.Four,
	[5] = Enum.KeyCode.Five,
	[6] = Enum.KeyCode.Six,
	[7] = Enum.KeyCode.Seven,
	[8] = Enum.KeyCode.Eight,
	[9] = Enum.KeyCode.Nine,
	[10] = Enum.KeyCode.Zero
}
InputHandler.Settings.MaxHotbarSlots = 10 -- This value should not be higher than 10

InputHandler.GUI = nil
-- Setup everything so we can start controlling the CTools
function InputHandler:Setup()
	-- Load the Gui
	self.GUI = self.Assets.ToolBar:Clone()
	self.GUI.Parent = LocalPlayer.PlayerGui
	-- Create the function in charge of handling all of our keypresses
	local function ActionHandler(Action,InputState,InputObject)
		if InputState == Enum.UserInputState.Begin then
			local ID = tonumber(Action)
			local CToolSelected = CTool.InventoryRecords[LocalPlayer.UserId].Backpack[ID]

			if CToolSelected.IsEquipped == true then
				CToolSelected:Unequip()
			else
				CToolSelected:Equip()
			end

		end
	end
	-- Connect events
	CTool.OnCToolOwnershipToLocalPlayer:Connect(function(OwnedCTool)
		-- Create our GUI for the Toolbar
		local NewToolFrame = self.GUI.ToolFrame:Clone()
		NewToolFrame.Name = OwnedCTool.ID
		NewToolFrame.NameLabel.Text = OwnedCTool.Name
		NewToolFrame.Visible = true
		-- Set up CTool inside a local hotbar slot
		if self.HotbarSlotsInUse <= self.Settings.MaxHotbarSlots then
			self.HotbarSlotsInUse += 1
			NewToolFrame.Parent = self.GUI.Hotbar
			
			for Slot = 1, self.MaxHotbarSlots,1 do
				if not self.Hotbar[Slot] then
					self.Hotbar[Slot] = OwnedCTool.ID
					NewToolFrame.NumberLabel.Text = Slot
					
					ContextActionService:BindAction(OwnedCTool.ID, ActionHandler,false, self.Keybinds[Slot])
					break
				end
			end
		else
			NewToolFrame.Parent = self.GUI.InventoryMenu
		end
	end)
	CTool.OnCToolRemovedFromLocalPlayer:Connect(function(CToolID)
		-- Removes the GUI Frame for the CTool, from the hotbar/Toolbar GUI
		self.GUI.HotBar[tostring(CToolID)]:Destroy()
		-- Clears the hotbar slot which references the CTool ID
		for Slot = 1, self.Settings.MaxHotBarSlots,1 do
			if self.HotBar[Slot] then
				ContextActionService:UnbindAction(CToolID)
				self.HotBar[Slot] = nil
			end
		end
	end)
	CTool.OnCToolEquipped:Connect(function(EquippedCTool)
		-- Show the GUI effects
		self.GUI.HotBar[EquippedCTool.ID].Outline.Visible = true
	end)
	CTool.OnCToolUnequipped:Connect(function(EquippedCTool)
		-- Show the GUI effects
		self.GUI.HotBar[EquippedCTool.ID].Outline.Visible = false
	end)
end

return InputHandler

Ill publish it as a resource once its fully ready, Let me know what you guys think!

7 Likes

Very cool, but I don’t see this becoming the next best character replacement due to the fact there’s a ton, I mean a ton of bug’s in the system not to mention this in its self is a bad idea,

You’re making two objective claims without explanation or evidence:

What kind of deal-breaking bugs are there in the system?

Why is a server-authoritative character controller a bad idea? I think it’s a really clever solution.

Currently, in most games, the player’s character is owned by the client. It’s an easy solution, but very exploitable.

The idea of Chickynoid is to let the server own the character. By using deterministic movement code, the client can provide an input and run the outcome before the server can respond and come to the same solution. So, input lag is minimal and the security is bulletproof.

Of course, it requires a lot of development since the entire character controller is being written from scratch. But once this is production-ready or if Roblox takes attention, character-based exploits are practically ineffective.

tl;dr: Chickynoid is not an anti-exploit. It does not respond reactively to abuse at the edge. Instead, it solves the problem at the root.

13 Likes

I have been using it for developement and have not found any issues that are game breaking or anything, the maximum I found was the fast delta time exploit to slightly give players a higher jump boost (its like very minimal).

Also saying this is a bad idea is a bit silly considering all triple A titles out there you see use this solution already.

4 Likes

The mod has been released as an alpha, and I think its on a semi stable state, and also utilizes chickynoid features and works with mods!

Make sure to check it out if you are interested in learning about writing mods for chickynoid or wanna learn how to make simple networking with it, or you are just looking for an inventory system for chickynoid.

Chickytools [alpha V1.0.3],A tool based inventory system for chickynoid! - Resources / Community Resources - DevForum | Roblox

1 Like

does it work for R6? because I only found R15 examples

Yes it does!

image

Get an R6 rig and name it to “R15Rig” then simply use it to replace the one located on here
image

Then go into the CharacterModel module script and make sure to have the hip set to this or your preference for your R6 rig to not be clipping into the ground
image

Make sure to put all your deffault animations inside the Rig’s humanoid’s animator as animation instances with these names
image

Simple as that!

8 Likes

Thank you for writing that up! You should submit it as a documentation PR :smiley:

3 Likes

Is this still under development? The last update to the GitHub was 4 months ago.