Simulating a lot of projectiles using FastCast and FE

  1. What do you want to achieve?
    I want to allow players to fire a large amount of projectiles without causing (mostly fps) lag.

  2. What is the issue? Include screenshots / videos if possible!
    I allow players to build their own spacships and they can place weapons on them. When a lot of projectiles are fired, client side framerates drop massively. I feel like they are dropping way lower than they should with the amount of bullets than I am generating.

  1. What solutions have you tried so far?

I am using the FastCast module. Whenever a player fires their weapons I simultaneously render the projectiles on the client using fast cast, and fire a remote event to the server. The server notifies all clients and they then render the bullets (unlesss this client is the one who fired, since he has already rendered them before firing the remote event).

I have tried to include the relevant pieces of code.

CLIENT_SIDE

local BULLET_UPDATE_RATE = 1 / 30 * 1000

-- TODO: check out if this can be more effiicent
local caster = FastCast.new()

local module = {}

local bullet = Instance.new("Part")
bullet.Anchored = true
bullet.Size = Vector3.new(1, 1, 3)
bullet.BrickColor = BrickColor.Red()
bullet.CanCollide = false
bullet.Material = Enum.Material.Neon

module.replicateBulletHelper = function(origin, directionWithMagnitude, velocity, blacklist)
    local part = bullet:Clone()
    part.Parent = workspace
    part.CFrame = CFrame.new(origin, origin + directionWithMagnitude.Unit)

    local ray = caster:FireWithBlacklist(origin, directionWithMagnitude, velocity, blacklist, part)

    local epochDisplacement = 0
    caster.LengthChanged:connect(
        function(origin, lastPoint, rayDir, displacement, cosmeticBulletObject)
            epochDisplacement = epochDisplacement + displacement
            if epochDisplacement < BULLET_UPDATE_RATE then
                return
            end
            epochDisplacement = 0
            cosmeticBulletObject.Position = lastPoint
        end
    )
    caster.RayHit:connect(
        function(hit, point, normal, material, cosmeticBulletObject)
            cosmeticBulletObject:Destroy()
        end
    )
end

SERVER SIDE

function Ship:fireManualWeapons()
	for index, manualWeapon in pairs(self.manualWeapons) do
		local barrel = manualWeapon.component:getModel():FindFirstChild("Barrel")
		if not barrel then
			error("Tried to fire manual weapon with no barrel")
		end
		local range = self.range
		local direction = barrel.CFrame.LookVector
		local directionWithMagnitude = direction * range
		local velocity = self.velocity
		local origin = barrel.Position
		
		local blacklist = { manualWeapon.component:getModel() }
		
		self.networkManager:getServerToAllClientsEvent("replicate_bullet"):FireAllClients(origin, directionWithMagnitude, velocity, blacklist, self.owner.UserId)
		
		local ray = manualWeapon.caster:FireWithBlacklist(origin, directionWithMagnitude, velocity, blacklist)
		manualWeapon.caster.RayHit:connect(function(hit, point, normal, material)
			-- do actual hit detection here
		end)
	end
end

I am assuming i am performing some inefficient logic somewhere, but I cannot seem to nail it down. So i guess my question is, how can i optimize this?

Thanks in advance!

I’m not sure. I’m dumb and and handle the casting on the server. Following!