Making a combat game with ranged weapons? FastCast may be the module for you!

You are barely handing over any data, also why are you handing settings over to the server that’s bad practice. You should do all checks server-sided.

I hand over settings because I have no way to check the settings on the server. Better said, I have no way to access the place settings are referenced.
Here’s how it currently works
Gun:
Client (Contains logic etc)
Settings (Contains all characteristics)

Gun sends information to server, server is a single handler that references a module script for how the gun hit detection and all that logic should behave. The Settings table provides all the info like, muzzle velocity, spread, and a multitude of other things. The server then simply uses given information to cast without any cosmetic bullets as that’s all handled client side.

Yeah that’s wrong because an exploiter can just change all that data up, also there are many ways you can go about what you said. You can have a table of different gun characteristics and then you check the gun type on the server and get the settings based off of that. If the settings are customizable by the user do datastore checks to ensure the player is eligible to use them.

Regardless, this doesn’t look like much data being sent at the server at all. Can you send a video of the guns in action and maybe provide code?

Ill show you the client fire function and the server cast and handover

Client
local function fire()
	local now = tick()
	--print("Fired function")
	
	--print(mousePos)

	mousePos = mouse.Hit.Position
	if heldFire then
		if now - lastFire >= Settings.FIRE_RATE then
			--print(now-lastFire)
			--print(now-lastFire >= Settings.FIRE_RATE)
			lastFire = now
			if Gun.ClipAmmo.Value > 0 then
				FireTrack:Play()
				if Settings.BULLETS_PER_SHOT > 1 then
					Shotgun:FireServer(Gun,Settings)
				end
				for i=1,Settings.BULLETS_PER_SHOT do
					print(i)
					if Settings.FIRE_MODE == "Burst" then
						if Burst < Settings.SHOTS_PER_BURST then
							CastHandler:firePrimary(Gun,Gun.Barrel.FirePoint,mousePos,Settings,Gun.Parent,false,nil,nil) --all cosmetic
							FireHandler:FireServer(Gun.Barrel.FirePoint.WorldPosition,mousePos,game.Players.LocalPlayer.Name) --Pure fastcast for hitdetection
							print("Fired C")
							camShake:ShakeOnce(random:NextNumber(.1,5),random:NextNumber(1,3),.1,.1)
							
							Burst += 1
						else
							Burst = 0
							heldFire = false
						end
					else
						CastHandler:firePrimary(Gun,Gun.Barrel.FirePoint,mousePos,Settings,Gun.Parent,false,nil,nil)
						FireHandler:FireServer(Gun.Barrel.FirePoint.WorldPosition,mousePos,game.Players.LocalPlayer.Name)
						print("Fired C")
						camShake:ShakeOnce(random:NextNumber(.1,5),random:NextNumber(1,3),.1,.1)
					end
				end
			end
		end
	end
end
Server Caster
function CastHandler:firePrimary(FirePoint,mousePos,player)
	LocalPlayer = player
	LocalSettings = require(game.Players[player].Character:FindFirstChildWhichIsA("Tool"):FindFirstChild("Settings"))
	CastParams.FilterDescendantsInstances = {player.Character, workspace.Bullets}
	
	local origin = FirePoint
	local direction = (mousePos - origin).Unit
	local directionalCF = CFrame.new(Vector3.new(),direction)
	local calculatedSpread = RNG:NextNumber(LocalSettings.MIN_SPREAD,LocalSettings.MAX_SPREAD)
	local TauThing = RNG:NextNumber(0,TAU)

	local direction = (directionalCF * CFrame.fromOrientation(0,0,TauThing)* CFrame.fromOrientation(math.rad(calculatedSpread),0,0)).LookVector
	local modifiedBulletSpeed = direction*LocalSettings.MUZZEL_VELOCITY
	--print("Recieved Direction ",direction)
	CastBehaviour.MaxDistance = LocalSettings.MAX_RANGE
	Caster:Fire(origin,direction,modifiedBulletSpeed,CastBehaviour)
end
Handler Handover
local RS = game:GetService("ReplicatedStorage")
local FireHandler = RS.Events.FireHandler

local CastHandlerRedux = require(RS.CastHandlerRedux)

FireHandler.OnServerEvent:Connect(function(player,FirePoint,mousePos)
	CastHandlerRedux:firePrimary(FirePoint,mousePos,player.Name)
end)

Note: I took your advise and omitted settings from being sent from the client, the server now finds its own way to check the settings. This resulted in aboue 3-4 KB/s drop but still not entirely satisfactory for me.

Is this a single player game considering you aren’t showing the cosmetic effects to other players? Also you should validate the firerate on the server. Other than that it looks good to me.

Its for multiplayer, and cosmetics are being fired to other players by other means on an alternate channel using a system with slightly higher latency.
I’m still not happy with this system as a single automatic weapon can sent over 7KB/s at a .1 interval. And this bridge net you speak of, it can reduce that?

Say I don’t care about the physics of bullet drop, will client sided tween with fireallclients be smooth? Body velocity bullets are laggy right but if they are client sided cloned bullets fired with body velocity, will it still lag? To confirm this module is for physics applied projectiles that aren’t laggy correct? But to be more precise it is tailored to the physics bullet stuff?

I noticed when using this module with PartCache for machine gun bullets that random meshes in the environment would flicker when the bullet impacted the wall. I figured out it seems to be caused by the PartCache bullets being returned so far away and then being re-used right after.
Changing
local CF_REALLY_FAR_AWAY = CFrame.new(0, 10e8, 0)
to
local CF_REALLY_FAR_AWAY = CFrame.new(0, -220, 0)
fixes the issue. I assume returning it so far away does something odd with the render engine or something idk.

1 Like

How expensive is it to use FastCast.new()? Is it something I should be precaching as much as possible, or is it fine to make a new one any time I define a new gun?

edit: didn’t mean to reply but good info thanks

1 Like

It’s something you should generally cache as much as possible. On the client it’s fine to make it when respawning, for example, or when giving the player a completely new gun.

Basically, what matters is that you don’t create a new one when you could sensibly already have an old one to use that is readily accessible.

How would I measure the amount of studs fastcast has pierced through?

Hello! I was wondering how to fix the projectile rendering lag? Possibly a solution or change you could make? Or a temporary solution I could add? Thanks.

I’ve managed to reduce the amount of data being passed to the server for server based hit detection but something else is now bothering me.

There’s a noticeable delay between client and server casts. The client is obviously faster and handles all cosmetic stuff. The client fires to all other clients giving it cosmetic data on where the casts should be aimed and fired and all that.

The server handles purely casting and hit detection to reduce load on the server as my game has heavy reliance on guns.

Refer to this screenshot,
Red - Client trajectory
Blue - Server trajectory
Green - Client’s lateral movement

The server trajectory is milliseconds delayed behind the client’s which is still noticeable as in my game players move at high speeds making this delay have very noticeable effect.

A rundown on how the code works is that in the same client script, the client requires a CastHandler dedicated for simply cosmetic effect with no hit detection, while the server requires a special CastHandler dedicated for only bullet simulation and hit detection fired over the BridgeNet community module service as a foundation pre-empting high server loads.

Question now is, what can I do to minimise the delay or sync these two trajectories without sacrificing the blood sweat and tears ive put into network optimisation?

Can I have multiple casters in a game (not the same script)?? I have a spell shooter for my wand but the NPC projectiles just don’t work as shown below:

https://i.gyazo.com/5b2b9e32a153ba311a0f32ddfe8485df.mp4

The code is the exact same as the wand (which works)

Syncing the client prediction with server’ state can be a pretty complicated thing to pull off, especially considering how limited remotes are.

I think the easiest solution you could do here is just slowly lerp the cosmetic from the client’s prediction over to where the server says it should be (If/When that information does get received, of course). FastCast wasn’t really designed for this kind of thing so you might have to tweak a bit of the internal code to get an ok enough result.

The higher the velocity the farther the cosmeticbullets spawn at. anyway to fix even if its a “visual bug”

Could you elaborate on this idea?

Here’s how I would think it would go

  • First raycast gets fired on Client, at normal speed

  • Cosmetic gets interpolated along first raycast’s path

  • Client informs Server that it raycasted

  • Server informs Client where it thinks the client was when it raycasted

  • Server does it’s own raycast from where it thinks the character is (In the past for the Client, of course)

  • Client does a second, sped-up raycast that catches up with the first and interpolates the cosmetic to that new raycast

Obviously I’m no expert so take my recommendation with a grain of salt.

Hey so, no idea if someone already asked this but… are projectiles that move in an arch motion (Bezier curves, basically) possible with this module? I’m not talking about using the workspace’s gravity, but something like this: Gyazo

Unless you play around the with the world forces, I don’t think so no, It’d be easier to just script your own projectile system like that and there are some pretty good tutorials out there. I’ve done it myself for a missile system I have.

1 Like