Optimizing FastCast and PartCache bullets

I have question about the AI and gun usage
Is the bullet hitscan? – if so you dont need fastcast
Are you rendering bullets on the client? – usually render stuff on the client and not on the server for better performance
You also dont have a Caster.CastEnd or whatever the destroy part of the ray is so you are only returning the part IF it hit also

if result.Instance:FindFirstAncestorWhichIsA('Model'):FindFirstChild('Humanoid') then
        local enemyHum =  result.Instance:FindFirstAncestorWhichIsA('Model').Humanoid
	enemyHum:TakeDamage(5)
end
				

can be

local enemyHum = result.Instance:FindFirstAncestorWhichIsA('Model'):FindFirstChild('Humanoid')
if enemyHum then
	enemyHum:TakeDamage(5)
end

the edit was cause i accidentaly submitted it too early

3 Likes

Render the bullets on every client not the server do that by using FireAllClients on an RemoteEvent.

Remember to protect your RemoteEvents!

Also one quick thing to note please use Animator:LoadAnimation and PivotTo instead it will most likely improve performance with your code!

4 Likes

Sorry about that, the script is included in an AI named ‘Conscript’, that is why I mentioned it.

The bullet isn’t really hitscan, my AI.Gun script casts one raycast (without fastcast) to check if a player is in sight, and if it isn’t, it fires an inefficient pathfinding script to get closer to the player, then the local function ‘Fire’ is fired which does FastCast:Fire() which fires a partcache bullet at the player.

I am not rendering bullets on the client, would it make a difference as the ai will always be visible by the player pretty much and it would be a pain to make it client based, I would probably have to spend atleast a whole day debugging the mess that it would create.

thanks for the Caster.CastEnd tip though! I will implement that in right now.

animator:LoadAnimation()? Is that located in the humanoid? Thanks for the tip, but again, I am skeptical about migrating this whole script to the client, would that make a big impact?

Yes it is located in the humanoid. And yes it would make a big impact!

1 Like

Hi, sorry for not marking your post as the answer, I am just waiting for a response on this dev forum post to see if it reduces the lag, I will mark your post as the answer once I get an answer on this post (god that was confusing to say), thanks again.

1 Like

Sorry, but it didn’t work, I tried rendering fastcast bullets and doing everything on the client, but that just made it much worse, here is a video showing the performance:


I spent several days working on this, I am tired, I don’t know what to do, I made a topic about this as you saw and it didn’t get any replies for a week, here is the script:

--edit: this is a local script
local ReplicatedStorage = game:GetService('ReplicatedStorage')
local Remotes = ReplicatedStorage.Events
local Event = Remotes[script.Name]
local FastCast = require(ReplicatedStorage.FastCastRedux)
local PartCache = require(ReplicatedStorage.PartCache)

ReplicatedStorage.Events.FastCastClient.OnClientEvent:Connect(function(NPC,Type,attachment,direction,velocity)
	if Type == 'Constructor' then
		local Caster = FastCast.new()

		local behaviour = Caster.newBehavior()
		local raycastParams = RaycastParams.new()
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
		raycastParams.FilterDescendantsInstances = {NPC,workspace.Projectiles,workspace.OreSpawningArea}


		local bulletTemplate = Instance.new('Part')
		bulletTemplate.Size = Vector3.new(0.2,0.2,12)
		bulletTemplate.Material = Enum.Material.Neon
		bulletTemplate.Color = Color3.fromRGB(255, 225, 0)
		bulletTemplate.CanCollide = false

		local CachedBullet = PartCache.new(bulletTemplate,100,workspace.Projectiles)

		behaviour.RaycastParams = raycastParams
		behaviour.MaxDistance = 300
		behaviour.AutoIgnoreContainer = false
		behaviour.CosmeticBulletContainer = workspace.Projectiles
		behaviour.CosmeticBulletProvider = CachedBullet

		Caster.LengthChanged:Connect(function(cast,lastpoint,direction,length,velocity,bullet)
			if bullet then
				local bulletlength = bullet.Size.Z/2
				local offset = CFrame.new(0,0,-(length - bulletlength))
				bullet.CFrame = CFrame.lookAt(lastpoint,lastpoint + direction):ToWorldSpace(offset)
			end
		end)
		
		Caster.CastTerminating:Connect(function(cast)
			local cosmeticBulletObject = cast.RayInfo.CosmeticBulletObject
			if cosmeticBulletObject ~= nil then
				CachedBullet:ReturnPart(cosmeticBulletObject)
			end
		end)

		Caster.RayHit:Connect(function(cast,result,velocity,bullet)

			local enemyHum = result.Instance:FindFirstAncestorWhichIsA('Model'):FindFirstChild('Humanoid')
			if enemyHum and result.Instance:FindFirstAncestorWhichIsA('Folder').Name == 'Allies' then
				ReplicatedStorage.Events.FastCastClient:FireServer(enemyHum,5)
			end
		end)

		function Fire(firepointAttachment,direction,velocity)
			Caster:Fire(firepointAttachment.WorldPosition,direction,velocity,behaviour)
		end

	elseif Type == 'Fire' then
		Fire(attachment,direction,velocity)
	end
end)

I am stuck, I have no clue what i’m doing wrong, I tried doing partcache on the server and sending it to the client, it didn’t work, I tried doing things on the server and only doing rendering parts on the client, it didn’t work, I have no clue what to do, please advise me on things I can do to get an answer on this issue, how to write a dev forum post better so that it gets a reply, I just want to get this thing done

1 Like

Hmmm… I am making a Gore System in the meantime however afterwards I will focus on one of my most important projects which is titled: RenderingService you can render objects in a VPF and in theory it should reduce lag greatly objects such as: Bullets, Bulletholes, Blood, etc.

2 Likes

You’re creating a new caster for everytime the client makes the bullet, there should only be one caster. In the FastCast API, it only states that it should act as the entire gun or projectile system and not a bullet

That is why I send an event with the ‘Type’ of constructor every time an npc is created, to build the caster once and then I send the ‘Type’ of Fire whenever I want the npc to fire, it sounds confusing but I am not making a new caster every time an npc fires, here is a picture showing the results of what happens when I add ‘print(new caster created!)’ on top of the ‘if Type == ‘Constructor’ then’ and spawn 20 npcs:
image
would making a single caster for 20 or more npcs work?

1 Like

How I do it is i create a server side module which does all the calculation and damage and have the client do all the visuals and stuff

Server side

local module = {}
local fastcast = FASTCAST
local caster = fastcast.new()
local castBehaviour = fastcast.newBehaviour()
local projectileVisualizer = YOUR REMOTE EVENT

function module.fire(origin,direction,velocity,acceleration,distance,raycastparams,projectile)
     castBehaviour.Acceleration = acceleration
     castBehaviour.MaxDistance = distance
     castBehaviour.RaycastParams = raycastparams
     caster:Fire(origin,direction,velocity,castBehaviour) 
     projectileVisualizer:FireAllClients(origin,direction,velocity,acceleration,distance,raycastparams,projectile)
end
caster.RayHit:Connect(function(...)
        do your damage stuff here
end

return module
local fastcast = FASTCAST
local caster = fastcast.new()
local castBehaviour = fastcast.newBehaviour()
local projectileVisualizer = YOUR REMOTE EVENT

projectileVisualizer.OnClientEvent:Connect(function(origin,direction,velocity,acceleration,distance,raycastparams,projectile)
     castBehaviour.CosmeticBulletTemplate = projectile
     castBehaviour.CosmeticBulletContainer = workspace
     castBehaviour.Acceleration = acceleration
     castBehaviour.MaxDistance = distance
     castBehaviour.RaycastParams = raycastparams
     caster:Fire(origin,direction,velocity,castBehaviour) 
end
caster.LengthChanged:Connect(function(cast,lastpoint,direction,displacement,vel,part)
    part.CFrame = CFrame.new(lastpoint,lastpoint + (dir*displacement))
end)

Honestly, theres probably much more efficient ways to do this but this has always worked for me. Doing all the damage calculations on the server also makes it more secure

1 Like

Honestly I don’t know what to do anymore


This was meant to be a very simple projectile system, how do the games like ‘The zombies onslaught’ manage all of those projectiles that they create per second?
its even worse now, with it reaching up to 8% but its logical to handle the rayhit on the server instead of the client, I am completely stuck.

edit: now I am casting 3 rays at once instead of a single one on the client

edit: the script itself isn’t lagging really, it spikes massively when the player respawns/gets targetted by the ai by about 4%, it seems to sit at a stable 2% when the player isn’t targetted.

edit: not really I am going insane I have no clue what to do

Yeah I somehow need to handle like 600 or 700 raycasts (and projectiles (in this case using fastcast and partcache)) every second, and I know it is possible, but I am at a loss, and this topic died

I’m gonna start working on the module now!

1 Like

did you end up finishing that module? just checking lol

1 Like

You will definitely need to use parallel lua for that amount of raycasts (every frame?). You might be able to get all those to run at 60 fps on most devices, but, why do you need that many raycasts?

1 Like

No, I never did finish it, I abandoned the project like a year ago after I couldnt fix the performance issues sadly.

I think you can’t really optimize it without modules. yes i love them.

1 Like

Would you do this per weapon? or for all weapons in the game?