Hello everyone! I am currently making a replication system that is able to replicate entities with Physics to clients, not full Physics but atleast falling, jumping and stuff like that!
Article Used for the Physics in this System
I am wondering how i could improve, and if you guys have any solutions for my current issue / how i should do it.
My current issue:
![]()
Too many Entities currently stress the server way too much, and if their Goal CFrames change too rapidly the server exhausts.
I am still planning to add some stuff to this System, but i want to focus on optimizing it first, here’s a video of it working with 100 Entities and the performance: Watch 2026-01-23 17-39-55 | Streamable
Currently for every single Entity, i do these calculations when a new Goal CFrame is set for them:
local function Calculate_New_Instance_CFrame(Instance_ID: number, Given_CFrame: CFrame, Current_CFrame: CFrame): CFrame
local GIVEN_INSTANCE_DATA = (Replication_Service.Stored_Data.Instances[Instance_ID] or Replication_Service.Cached_Data.Instances[Instance_ID]);
local GIVEN_INSTANCE_EXTRA_DATA = Replication_Service.Stored_Data.Extra_Data[Instance_ID];
local GIVEN_INSTANCE_TYPE_DATA = INSTANCE_TYPES[GIVEN_INSTANCE_DATA.Instance_Name];
-- GET DATA RELATED TO THE INSTANCE, IF IT DOES NOT HAVE PHYSICS RETURN
if not GIVEN_INSTANCE_TYPE_DATA.Has_Physics then return Given_CFrame end;
local MoveSpeed = GIVEN_INSTANCE_EXTRA_DATA.MoveSpeed;
local INSTANCE_HITBOX = REPLICATED_OBJECT_STORAGE_FOLDER[INSTANCE_TYPES[GIVEN_INSTANCE_DATA.Instance_Name].Instance_Name].HumanoidRootPart.Instance_Hitbox;
local ORIGINAL_GIVEN_CFRAME = Given_CFrame;
local Final_Calculated_CFrame = nil;
-- Settings / Variables from the Given Instance
local Raycast_Params = RaycastParams.new();
local Velocity = GIVEN_INSTANCE_DATA.Velocity;
local JUMP_MULTIPLIER = 0.5;
local FALL_SPEED = 2;
local ROTATION_SPEED = 8; -- I think lower values make NPCs feel less robotic.
local JUMP_DELAY_TIME = 0.1; -- Add some delay so its doesn't over inf jump.
--Raycast_Params.BruteForceAllSlow = true;
--
local Size = INSTANCE_HITBOX.Size;
local Size_Y = Size.Y;
local Size_Z = Size.Z;
local Half_Z = Size_Z / 2;
local Half_Y = Size_Y / 2;
--
local Z_CFrame = CFrame.new(0, 0, -Half_Z);
local Down_Vector = Vector3.yAxis * -Size_Y;
--local lastJumped = os.clock()
local deltaTime = task.wait();
local ORIGINAL_POSITION = Current_CFrame.Position;
-- Main Logic, runs until a valid CFrame is found
while true do
local Current_Position = Current_CFrame.Position;
local New_MoveSpeed = deltaTime * MoveSpeed;
local Movement_CFrame = CFrame.new(0, 0, -New_MoveSpeed);
local Front_Raycast_Result = workspace:Raycast(Current_Position, Current_CFrame.LookVector * (Size_Z + New_MoveSpeed), Raycast_Params);
local HAD_CHANGES = "";
if Front_Raycast_Result then
Movement_CFrame = CFrame.new(0, 0, -Front_Raycast_Result.Distance + Half_Z);
HAD_CHANGES = "Wall";
--if Velocity == 0 and workspace:GetServerTimeNow() - Physics_Data.Last_Jumped > JUMP_DELAY_TIME then
-- Velocity = Distance_Function(Current_Position, Given_CFrame.Position) < 6 and 0 or JUMP_MULTIPLIER Replication_Service_Client.Physics_Instances[Instance_ID].Last_Jumped = workspace:GetServerTimeNow();
--end
end
local Falling_CFrame = CFrame.new(0, 0, 0);
local FALLING_RAY_DIRECTION = Vector3.yAxis + Down_Vector;
local FALLING_RAY_POSITION = Current_Position + Vector3.yAxis * Half_Y;
local Down_Raycast_Result = workspace:Raycast(FALLING_RAY_POSITION, Vector3.new(0, -25, 0), Raycast_Params);
local i = 1;
if Down_Raycast_Result then
Falling_CFrame = CFrame.new(0, -Down_Raycast_Result.Distance + Size_Y, 0);
HAD_CHANGES ..= "_Fall";
end
local _, Yaw = CFrame.new(Current_Position, Given_CFrame.Position):ToOrientation();
local Old_Rotation = Current_CFrame.Rotation;
Final_Calculated_CFrame = CFrame.new(Current_Position) * CFrame.Angles(0, Yaw, 0) * Movement_CFrame * Falling_CFrame;
if HAD_CHANGES == "_Fall" then
local DIFFERENCE = tonumber(string.sub(tostring(Final_Calculated_CFrame.Y), 1, 5));
if (DIFFERENCE - tonumber(string.sub(tostring(Current_Position.Y), 1, 5))) <= 0.25 then
HAD_CHANGES = "";
end
end
Current_CFrame = Final_Calculated_CFrame;
if HAD_CHANGES ~= "" or (Current_CFrame.Position - Given_CFrame.Position).Magnitude <= 0.8 then
break;
end
end
return Final_Calculated_CFrame;
end
The main issue with is that i can’t really find a solution to, or i am just clueless, is that first off i am running this possibly multiple times whenever i execute this Function, because i have to basically “step” the Entity forward to check if they need to fall, or if there is a wall in front of them.
I can’t just do one big raycast because then the Entity might just skip a hole.
![]()
And then when the Entity is just walking around sometimes the Y Position on the server changes slightly for some reason, so my solution to that was to do some string stuff with the Y position to shorten the decimal count, since the difference was very small. But that could be very performance heavy as well. (This is in the part HAD_CHANGES == "_Fall")
![]()
I am heavily wondering on what i need to do to improve this System, because this is also my first time doing something like this, i could show the Client as well if needed, but the Client works fine!
Thanks for any help that might be provided :).
UPDATES:
My goal for this system is 300 Entities maximum, i even added a Render Distance System to try and counter some of the stress that the server can have. But still it would be too much with this current system



