Custom character question

Sorry for the repost, but my older topic got taken down for being in the wrong category. I previously asked about creating a custom character controller that does not use the default humanoid. I was able to get a few great steps for that, but I was wondering how to make the player have client ownership like the default.
I am pretty sure the player normally is controlled by the client to reduce delay, but does Roblox validate it on the server? Overall I am wondering how much of the character controller Roblox gives you by default, and how much if any would I need to recreate for a custom one.
Thank you!

Creating a custom character controller in Roblox that does not use the default Humanoid can be a complex task, but it allows for greater customization. Here’s a breakdown of what you need to consider and some steps to help you achieve this:

Client-Server Ownership and Validation

In Roblox, the default character controller uses a combination of client and server processing to provide smooth and responsive character movement. Here’s how it generally works:

  1. Client-Side Control: The client handles the immediate input and movement to ensure responsiveness. This means when a player presses a key to move, the client immediately updates the character’s position.

  2. Server-Side Validation: The server periodically validates the character’s position and movement to prevent cheating. The server receives the movement data from the client and checks it against the game rules.

Steps to Create a Custom Character Controller

  1. Create the Custom Character Model:

    • Design your character model in Roblox Studio (e.g., using parts and welds).
    • Make sure to include necessary components like PrimaryPart for easier manipulation.
  2. Handle Client-Side Input:

    • Use UserInputService or ContextActionService to capture player input.
    • Update the character’s position and orientation based on input.
  3. Replicate Movement to the Server:

    • Use RemoteEvents to send movement data from the client to the server.
    • On the server, validate the movement data and update the character’s position.
  4. Smooth Movement:

    • Implement interpolation on the client to smooth out the movement based on the server updates.
    • This helps reduce jittering due to network latency.

Here’s a simple example to get you started:

Client Script (LocalScript):

-- Place this LocalScript in StarterPlayerScripts

local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local remoteEvent = game.ReplicatedStorage:WaitForChild("MovementEvent")

local speed = 16
local direction = Vector3.new(0, 0, 0)

local function onInputBegan(input, processed)
	if processed then return end
	if input.KeyCode == Enum.KeyCode.W then
		direction = direction + Vector3.new(0, 0, -1)
	elseif input.KeyCode == Enum.KeyCode.S then
		direction = direction + Vector3.new(0, 0, 1)
	elseif input.KeyCode == Enum.KeyCode.A then
		direction = direction + Vector3.new(-1, 0, 0)
	elseif input.KeyCode == Enum.KeyCode.D then
		direction = direction + Vector3.new(1, 0, 0)
	end
end

local function onInputEnded(input, processed)
	if input.KeyCode == Enum.KeyCode.W then
		direction = direction - Vector3.new(0, 0, -1)
	elseif input.KeyCode == Enum.KeyCode.S then
		direction = direction - Vector3.new(0, 0, 1)
	elseif input.KeyCode == Enum.KeyCode.A then
		direction = direction - Vector3.new(-1, 0, 0)
	elseif input.KeyCode == Enum.KeyCode.D then
		direction = direction - Vector3.new(1, 0, 0)
	end
end

UserInputService.InputBegan:Connect(onInputBegan)
UserInputService.InputEnded:Connect(onInputEnded)

RunService.RenderStepped:Connect(function(dt)
	local moveVector = direction.Unit * speed * dt
	if direction.Magnitude > 0 then
		character:SetPrimaryPartCFrame(character.PrimaryPart.CFrame + moveVector)
		remoteEvent:FireServer(character.PrimaryPart.Position)
	end
end)

Server Script:

-- Place this Script in ServerScriptService

local Players = game:GetService("Players")
local remoteEvent = Instance.new("RemoteEvent")
remoteEvent.Name = "MovementEvent"
remoteEvent.Parent = game.ReplicatedStorage

remoteEvent.OnServerEvent:Connect(function(player, newPosition)
	local character = player.Character
	if character and character.PrimaryPart then
		local validPosition = true -- Add your own validation logic here
		if validPosition then
			character:SetPrimaryPartCFrame(CFrame.new(newPosition))
		end
	end
end)

Key Points:

  1. Input Handling: Capture player inputs and convert them to movement vectors.
  2. Remote Events: Use RemoteEvents to send movement data from the client to the server.
  3. Server Validation: Implement logic on the server to validate the movement data to prevent cheating.
  4. Interpolation: Smooth out the movement on the client side to handle network latency.

This is just a basic implementation. Depending on your game, you might need more complex validation

ignore that ai response,
i’m pretty sure roblox doesn’t validate the default character controller on the server at all, so any sanity-checking on the server would be an improvement

i’m not really sure what you mean by “client ownership”, do you mean physics network ownership or something else?

1 Like

I might have been a bit confused but I just meant how the server does not check it at all. So by default the regular controller could be teleported around and the server would not double check?

exactly. exploiters have(and probably still can) been able to teleport their client character wherever and it’s up to the game creator to put in server-side checks

Roblox gives complete authority of the character to the client. It’s why you see exploiters fly around and noclip.