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

…Yyyyyup.

That’s what I get for being tired while making that! Thanks lol. It’s patched now.

1 Like

Is there any way to add a blacklist to hats?

You would need to iterate through all of the characters in your game (and connect to every player’s CharacterAdded event to detect when they respawn) and add all of the accessories to a table. Pass this table into FireWithBlacklist.

What I do for hats is assign them to a collision group that can’t collide with anything

2 Likes

This is great! Makes it hella easier to create ranged weapons

Really loving it so far, and it’s quite easy if you know what you’re doing as well!
For those who doesn’t understand how to use this module, or can’t visualize how to use it, I’ll try my best to explain how I set mine up.

Scripts:

  1. FireScript (LocalScript, does the main shooting, no projectile handler, duh!)
  2. ProjectileHandler (LocalScript, does the client side projectile visual render)
  3. ServerHandler (Script, does the server side projectile contact)

Events:

  1. FireEvent (RemoteEvent, used to tell the server to fire)
  2. ClientProjectile (BindableEvent, used by the caster to create an instant client sided projectile visual)
  3. ReplicateProjectile (RemoteEvent, used by the server to tell other clients to create their side of projectile visuals)

Sequence:

  1. FireScript fires 2 things: ClientProjectile and FireEvent.
  2. ProjectileHandler listens for the ClientProjectile and runs the function VisualSetup that runs FastCast:Fire(origin, direction, velocity, bulletVisual), updating the visual position using FastCast.LengthChanged and destroying the bulletVisual with FastCast.RayHit.
  3. ServerHandler simultaneously listens for the FireEvent that runs FastCast:Fire(origin, direction, velocity), listening for the bullet hit using FastCast.RayHit. Directly after firing, the server then does ReplicateProjectile:FireAllClients(initialPlayer, …).
  4. ProjectileHandler listens for the ReplicateProjectile and runs the same function VisualSetup, but first checks if initalPlayer ~= LocalPlayer to avoid creating a second delayed visual.

In a nutshell: Client tells the server to shoot. Client also handles their own and others’ projectiles in one script, updating visual via LengthChanged. Server runs the identical fire function the client does, but handles the projectile connection via RayHit.

Remember, yours doesn’t have to be exactly like mine, this is just the general usage and will vary depending on how your gameplay framework is made.
You can find the arguments/parameters that are passed on the github link provided.

21 Likes

The question is… Are we going to get that penetration system :thinking:

I’ve been occupied with a lot of other stuff

I have a primary workflow set out, and the basic gist is that the user will specify a callback function that returns true or false (true for “yes it did hit”, false for “no, keep going”)

One thing I want to mandate is that this function must never yield as this disrupts the flow of the cast. I don’t quite know how to do this off the top of my head.

1 Like

If you want a bit of a status update for why this is so difficult, here’s the problems I have to solve:

  • How do I decide to pierce or not? (This is easy, just do a callback!)
  • How do I handle physics? Say we do hit a part and we want to pierce…
    • We need to add that part to an ignore list (which can get nasty really quick if the user is using stuff like a whitelist).
    • We can’t just skip ahead by the lost distance (e.g. say the cast would have gone 5 studs, we went 1, so just skip by 4)
      • We need to also find out how much time that cast would have taken if it were only supposed to go the given distance. This is inherently inaccurate since we can’t accommodate for potential lag, so for casts that simulate physics, we risk an effect similar to what I will call “bullet refraction” if we try to calculate trajectory from this information.
      • The only way to do this without issue is to keep the behavior consistent – Act like it’s one giant segment of time, and don’t try to divide it up. This means repeating the same cast over and over until we can reach the full distance or reach a conclusion (e.g. function says “okay, we hit this part now”). This is going to be incredibly difficult to emulate. The cost of this is that users can’t trace a bullet going through something like a pseudo-ballistic gel with a curved path, and I have a feeling that this goal is going to come up.

It’s a bit of a mess, but I’m working on it! :stuck_out_tongue:

1 Like

Alright everyone! Latest version is out!

I present to you: FastCast v 9.0.0 - The Piercing Update. This release is bound to have some bugs so please message me or reply here if you find anything wrong. Your CanRayPierce method must return before the next call to Heartbeat or RenderStepped (depending on the side it’s running on). If it doesn’t, it will throw an error.

It is now possible to specify a callback that enables bullet piercing. Here’s the example that was added to the example gun:

function CanRayPierce(hitPart, hitPoint, normal, material)
	-- This function shows off the piercing feature. Pass this function as the last argument (after bulletAcceleration) and it will run this every time the ray runs into an object.
	if material == Enum.Material.Plastic or material == Enum.Material.Ice or material == Enum.Material.Glass or material == Enum.Material.SmoothPlastic then
		-- Hit glass, plastic, or ice...
		if hitPart.Transparency >= 0.5 then
			-- And it's >= half transparent...
			return true -- Yes! We can pierce.
		end
	end
	return false -- No, we can't pierce.
end
11 Likes

Dose it matter a great deal if I call this module from the server or client?
What are the differences if done with one over the other?

It’s dependent on replication, and by extension, is like many other client/server setups where…

  • If you call on the server…

    • You get the benefits of
      • Only needing to run the code once across the entire game
      • Automatically replicating data to clients
    • You get the drawbacks of
      • Seeing bullet jittering again from ping/latency
      • Inconsistent hit registry when compared to the visuals of the client who fired the bullet
  • If you call on the client…

    • You get the benefits of
      • Perfect bullet simulation for every client individually
      • (If you do hit detection on the client) flawless hit registry, and, since this is not using a physical part but is instead using lua data, it is presumably very difficult to exploit the location of the bullet, making firing and detecting hits from the client a potentially safe option.
    • You get the drawbacks of
      • Needing to manually replicate casts to each client individually which requires a different scripting setup, one that isn’t too difficult if you are a more knowledgeable individual.
      • (If you do hit detection on the client) the potential (again, albeit very rare) for exploits.

Personally I have bias to doing everything on the client since FastCast’s underlying systems would require knowledge of Roblox’s encrypted lua VM to exploit adequately. This makes it a pretty good option to simply handle rendering and hit detection alike on the client.

8 Likes

Got it, Thanks.

Another thing I’m wondering: Dose /Will it support a ‘Universal Black list?’
(A blacklist things can be added to/removed from in real time, that will always be remembered by the module and can be used by all clients)

I kinda need this for my bullet detection to avoid hitting triggers and such.

Example: there’s a invisible non-colliding part (Not in the ‘Universal Blacklist’). If a bullet hits this part, it’s checked against some parameters
(Somthing like: if transparency ~=1 and CanCollide then…)

Once it fails the check, it’s added the ‘Universal Blacklist’ and the bullet continues as if it hadn’t hit anything. (The ray would then ignore it form then on so future bullets wouldn’t ever hit it again)

If this isn’t currently possible, would you consider looking into it for a future update?

It’s possible but you’d have to implement it yourself by hacking together something with the piercing system that I just added + your own blacklist.

Do you think you might add somthing like this in the future?

If not, I’ll figure somthing out, but I’d rather not edit the module directly so I can update it easier.

I shall now grant this the dog stamp and use it in every single FPS game i will make. the module does everything it needs to do perfectly, but some native support for auto replication (firing on the server has the bullet lagging behind a bit) to other clients would be cool.

3 Likes

I believe I’ve found a bug: I’m trying to use this with a shotgun I’ve made, but cannot get it to fire more then one bullet.
Is there somthing special I need to do to get it to work?

(Apologies for the bad formatting below, I don’t know how to post a code block)

for Shot =1,6 do
Projectile:FireWithBlacklist(
tool.Value.Fire_Point.Position, --Origin
direction *100, --Direction, *MAX_DIS
modifiedBulletSpeed, --Speed
{workspace.CurrentCamera}, --Ignore this
Tracer, --Tracer Part
false, --IgnoreWater?
Vector3.new(0,-15,0) --Gravity
)
end

I simply changed the script in my shotgun and instead of calling the Fire() function once I am calling it 5 times.

Also I changed the spread values from 0 - 2

This way I get a nice shotgun :))

Hmm, that still didn’t work for me…

I guess it might be somthing in my firing system?
Dose it work for you if you put your fire function in a ‘for’ loop like I did, instead of calling it multiple times manually?

Didnt try it.
here is my changed MouseEvent in the script

MouseEvent.OnServerEvent:Connect(function (clientThatFired, mouseDirection)
	if not CanFire then
		return
	end
	CanFire = false
	Fire(mouseDirection)
	Fire(mouseDirection)
	Fire(mouseDirection)
	Fire(mouseDirection)
	Fire(mouseDirection)
	wait(FIRE_DELAY)
	CanFire = true

end)