Gameplay abilities and Weapon Firing

So i currently have GAS implemented, and currently working on the weapon firing.

Now i know a lot of games, the weapon is fired on both client and server at the same time, this is fine, i can understand that, and its only one RPC to activate the firing ability. Issue is client sending its target data to the server, and server checking to see if hit was success against its own target data. I assume this would be the way it is done in Fortnite? But that is a lot of rpcs for a gun that fires 600 rounds per minute (.1 second per RPC). Granted not all bullets will hit and these can be rejected. But i can’t seem to get my head around an optimal way to handle this. I kinda realised in Fortnite that shots are not truly predicted, ie, damage is not applied till the server verifies (so client doesnt adjust health bars, altho i only noticed this in PVP in PVE i realise enemies do loose health but if the server disagrees i have seen health bars jump back up).

I was just hoping to get some input maybe also from some UE4 devs on the best practice for auto fire weapons. I also realised sending muzzle flashes as cues can hit the RPC limit for Cues. How did Epic get around this?

Right now my weapon is handled outside of the GA apart from activation the weapon fire (which is a predicted ability that activates the weapon and tells the FireMode to start firing).

Right now i produce target data inside the FireMode and send this via a Gameplay Event which activates an ability on Server only via a RPC and sends in the payload. Now this works, don’t get me wrong. But it seems like a lot of server RPC calls for every shot that is fired. Now i saw in a reply from Ratti that in Fortnite they batch the rpcs. But i don’t see any example of this, and each shot sending in a payload via a Server rpc seems quite expensive.

All info/suggesstions is fully appreciated

2 Likes

You don’t send each shot. You instead just send the “My weapon has begun firing” or “My weapon has stopped firing”. The client rotation and movement should already be replicated so you can construct the data on the server for where you should be doing your raycast or what not.

You can look at the Unreal Tournament or ShooterGame example for a more indepth look.

1 Like

UT4 does send a rpc per shot (specifically Hit Actor client side). Idea is for server to rewind the supposed hit clients position to find out if the hit would have happened when the client said

I am familiar and in no way new to this. It’s just i want to integrate the firing into the ability system but support a predicted nature of the hit against player pawns.

Hi Kaos. I’ll try to answer this the best I can though I need to give the standard disclaimer that this stuff is far from perfect. High rate of fire hitscan weapons weren’t the first class citizen when designing the ability system and I’ve frankly never seen an integration with it that felt great. We would do things differently if we ever wrote a new version. But that said, I think its workable and you get a lot of other advantages in using the ability system with your weapons, so don’t let that discourage you.

You are correct that in Fortnite, for the vast majority of hit scan guns, we send an RPC with each bullet shot. That is, 1 bullet = 1 ability activation -> 1 target data sync -> 1 ability end. For better or worse, that is how the FN weapon system evolved with the ability system. I’ll mention some alternatives at the end but I think you are most looking for “how Fortnite works”, so I’ll focus on that.

Given the above, out of the box this would generate three(!) RPCs. One RPC gives me heartburn, so three was a problem. That is what the RPC batching that you reference does. It condenses those three RPCs (ServerTryActivateAbility, ServerSetReplicatedTargetData, and ServerEndAbility) into a single RPC.

This batching technique is in the engine and something you should be able to make use of. I am not sure exactly what engine version it was first available in, but here is the github commit that has it (sorry its part of a large merge changelist, the relevant changes are in AbilitySystemComponent.h and AbilitySystemComponent_Abilities.cpp).

https://github.com/EpicGames/UnrealE…ab524fa9c88105 (Need to be logged into github to see)

Using it should be relatively straightforward… I think:


FScopedServerAbilityRPCBatcher ScopedRPCBatcher(ASC, PrimaryAbilitySpecHandle /** Your weapon's ability spec handle */);

That is the only line of code in Fortnite that enables the batching. It is at the top of our “TryToFireWeapon” function. I need to explain here that the “Fortnite Weapon System” sits between input bindings and the actual call to activate the gameplay ability that the weapon uses. If you are in a world where you bind input directly to ability activation, I think you could add this to UAbilitySystemComponent::TryActivateAbility and it would work. But that is untested. You may still need to create your own thin layer here.

The point is really this: you are about to call some function that may try to call ServerActivateAbility, ServerSetReplicatedTargetData, and ServerEndAbility within that single function scope. If you can put a FScopedServerAbilityRPCBatcher on the stack before that happens, it will suppress the calls to the actual RPCs, cache of the data you are trying to send, then call the batch RPC when the FScopedServerAbilityRPCBatcher goes out of scope (see UAbilitySystemComponent::CallServerTryActivateAbility, UAbilitySystemComponent::CallServerSetReplicatedTargetData, UAbilitySystemComponent::CallServerEndAbility). “ServerAbilityRPCBatch” is the actual batch RPC I am referring to.

That should be it… on the receiving side (server), it should unpack the parameters and call those three functions in a way that is transparent to the rest of the system.

So, that takes care of client->server communication. I will just mention that we also did batching on the server -> everyone else side with respect to gameplay cues. Each weapon shot can generate several GCs: the muzzle flash (predicted), the impact effect (predicted), the damage effect (not predicted), + other stuff (crits, etc - not predicted). By default each GC replicates independently, not as an RPC but as replicated data in the ability system component. And all of those GCs mostly share the same data (E.g, source/target, hit location, magnitude, ability level, etc). The optimization we did was to built another batching structure, intercept those specific GCs, and replicate them all together in a more efficient, less generic fashion.

The other alternatives I mentioned above are probably obvious: for automatic weapons you could just have 1 ability activation, N target data syncs, 1 ability end (so, don’t end the ability until input is released). And, yes, additionally if you want a more “pure” classic FPS shooting model, the client doesn’t need to tell the server who he hit. The target data can be generated server side based on the server’s view of the world. Of course that leads to more mispredictions and other issues that will crop up depending on how your server is running the game (E.g, its harder to do location based damage if your server doesn’t run animation code. Different frame rates between client and server make things harder to stay in sync for precise queries, etc.). For Fortnite, the fast paced building (lots of shot blocking actors being quickly created and destroyed) and 100 players make it hard to do traditional shooting models.

Hope that helps

4 Likes

Thanks , that has helped me a lot. This is kinda the idea i was working towards, although kind of struggling to make the batch rpc system work. But sure i can figure it out in due time. But the information/insight was awesome once again :).

I just have one more question, does the server run its own independant trace to confirm the hit? I assume fornite servers don’t run animations (to save on resource usages). Or does it trace from the same position the client said?

Best regards
-Daniel

I’m not as familiar with the current state of the server side verification code, it has evolved quite a bit over the last two years. I believe there is a trace done but its mainly to detect newly placed building actors (to lessen the chance that you see yourself being shot through walls you are building). We don’t run animations on the server so hit location/bone isn’t accurate and we don’t do server side rewind/lag compensation.

Thanks again for the info, seems i have gone a very similar route, which is nice to know :slight_smile:

Hi ,

I’m reading that as the Server is blindly accepting the client’s replicated TargetData. Is that correct? If so, how do you prevent clients from cheating and sending impossible TargetData?

It does not blindly accept: the server does a lengthy verification to prevent cheating. This is more the area of the anti cheat team so I can’t really give too many details. High level, its checking things like rate of fire, max number of targets, distance and angle to hit target, etc. It does do a trace but its more for ruling out impossible shots / penetrating buildings (“yes you could have hit that”) rather than authoritatively deciding what was hit (“based on my view of the world, this is what you hit”).

Hope that clarifies.

That does help, thank you!

Hi ,

Would you mind elaborating on this a bit more for a hitscan weapon in a multiplayer game?

I’m still very new to GAS, but this is the setup that I have so far:

  • When weapon is equipped, server gives Character ability to fire weapon
  • When weapon fire key is pressed, weapon fire ability is activated from client (local predicated)
  • ActivateAbility() creates a “Wait Target Data” task using class “AGameplayAbilityTargetActor_SingleLineTrace”
  • From “Valid Data” pin of “Wait Target Data” task I have a Branch “if Blocking Hit” (using “Get Hit Result From Target Data” from Data pin of task to determine if it is a blocking hit)
  • If it is a blocking hit, I apply GameplayEffect to Hit Actor which reduces Health Attribute and then call EndAbility

I’m still looking into where the “N target data syncs” part of your description fits in. I see that the AbilitySystemComponent has a ServerSetReplicatedTargetData() but I don’t see many examples of it being used, or how it fits into the system I described.

Also, I see a warning in the documentation for AGameplayAbilityTargetActor. Should I not be using the Gameplay Ability Target Actors to do the line trace?

Im currently experimenting in Blueprint until I understand the concepts, and then will be moving to C++ where it makes sense. Any additional comments, code samples or information would be appreciated!

Honestly, i wouldn’t use the Target Actors as they are, they are too expensive for weapon fire. Now it depends on what system you want to go for. Client produces shot data, or server and client produces shot data or just server produces the data. Truthfully, batching the shots should not be something you should do to start of with. i would get the system working. The most simplest way is :

A: Activate ability, which fires the first shot.
B: Have a task which is repeated after X delay (X being firerate of weapon). This task will do the line trace.
C: Depending if its client or server producing the target data, if its client producing data you would need to setup a scoped prediction window before sending the target data. This should be via CallServerSetReplicatedTargetData. If its server, then there is no need to call this as server can just produce and act on the target data itself.
D: Once firing is finished (out of ammo, trigger relased, etc), end the ability.

I mean my system is quite complex, as i don’t use any tasks in the ability, instead my weapon has native firemodes, which calls CurrentFireAbility->FireShot(). But the principle is the same. I am planning to do a bit of a write up on a more simpler system than mine, which will work, and makes use of the batched RPC calls in the ability system. Possibly also release a sample project showing it in action.

One thing to note, i don’t use ability input bindings for my weapons. Input is handled natively and forwarded to the current equipped weapon. Pressing fire, calls TryFireWeapon on the actual weapon itself.

One thing to note, you don’t want to grant the ability on equip, the ability should be granted when the weapon is given to the player. This reduces potential delay in firing when equipping as you have to wait for a onrep back from the server before client can fire.

So i got the core weapons working, just having an issue with fast firing guns like miniguns. With a RPC per bullet these guns rack up RPC calls galore. Is there any best practices for such weapons? Like batching shots into a single RPC? Wonder how other games manage this?

I wouldn’t do an event per bullet, or even an actor per bullet. Use a cone falloff model and just sent that and a bool representing whether it’s firing or not. Then figure out how much damage per second you want and apply a falloff rate as the overlap approaches the outside of the cone to simulate less bullets hitting it.

This has to work within the ability system, all weapon shooting is done locally and handled via Gameplay Ability. I really don’t want to completely special case the minigun

Did you solve it somehow ? :wink: