x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

RPC Confusion :S

I have a system that is made up of weapons and abilities. The abilities are components that are attached to the weapons to make them do something. For example, a pistol would have a line trace ability. Rocket launcher would have a projectile ability.

So, I have the usual setup where firing happens on the server and the clients only simulate this.

I will walk through my code.

First I have the character:

 // ****FPSCharacter.h****
 // Handles start weapon/ability fire
 void OnStartFire();
 
 // ****FPSCharacter.cpp****
 void AFPSCharacter::OnStartFire()
 {
     Cast<AFPSWeapon>(EquippedComponent)->StartFire();
 }

Next, I have the weapon.

 // ****FPSWeapon.h****
 // TODO: is there a way to do this without having server calls in both Weapon and Ability?
 // Start firing the weapon on the server
 UFUNCTION(Reliable, Server, WithValidation)
 void ServerStartFire();
 void ServerStartFire_Implementation();
 bool ServerStartFire_Validate();
 
 // Start weapon fire
 virtual void StartFire();
 
 // ****FPSWeapon.cpp****
 bool AFPSWeapon::ServerStartFire_Validate()
 {
     return true;
 }
 
 void AFPSWeapon::StartFire()
 {
     // Tell the server we want to fire
     ServerStartFire();
     
     // WHY CAN'T I JUST DO THIS HERE?
     // Get the ability components attached to this weapon
     /*TArray<UActorComponent*> AbilityComponents = GetComponentsByClass(UFPSAbilityComponent::StaticClass());
     if (AbilityComponents.Num() > 0)
     {
         // Execute the first ability
         Cast<UFPSAbilityComponent>(AbilityComponents[0])->ExecuteAbility();
     }*/
 }
 
 void AFPSWeapon::ServerStartFire_Implementation()
 {
     // Get the ability components attached to this weapon
     TArray<UActorComponent*> AbilityComponents = GetComponentsByClass(UFPSAbilityComponent::StaticClass());
     if (AbilityComponents.Num() > 0)
     {
         // Execute the first ability
         Cast<UFPSAbilityComponent>(AbilityComponents[0])->ExecuteAbility();
     }
 }
 

And the ability..

 // ****FPSAbility.h****
 UPROPERTY(Transient, Replicated)
 bool IsFiring;
 
 virtual void ExecuteAbility();
 
 UFUNCTION(Reliable, Server, WithValidation)
 void ServerStartAbility();
 void ServerStartAbility_Implementation();
 bool ServerStartAbility_Validate();
 
 UFUNCTION(Reliable, Server, WithValidation)
 void ClientStartAbility();
 void ClientStartAbility_Implementation();
 bool ClientStartAbility_Validate();
 
 
 // ****FPSAbility.cpp****
 void UFPSAbilityComponent::ExecuteAbility()
 {
     ServerStartAbility();
 }
 
 void UFPSAbilityComponent::ServerStartAbility_Implementation()
 {
     if (GetOwningCharacter()->Role == ROLE_Authority)
     {
         ClientStartAbility();
     }
 }
 
 bool UFPSAbilityComponent::ServerStartAbility_Validate()
 {
     return true;
 }
 
 void UFPSAbilityComponent::ClientStartAbility_Implementation()
 {
     GetOwningCharacter()->SetIsFiring(true);
 }
 
 bool UFPSAbilityComponent::ClientStartAbility_Validate()
 {
     return true;
 }

So, my question is..

Why does AFPSCharacter::ServerStartFire() need to be a server RPC since it calls a function that calls a Server RPC?

Originally I had it coded without AFPSCharacter::ServerStartFire(). Instead, I just had AFPSCharacter::StartFire() call the ExecuteAbility function. However, this was causing the ability logic to be called on the client instead.

This is confusing me. Can anyone break it down?

Thanks!

Product Version: UE 4.10
Tags:
more ▼

asked Feb 01 '16 at 09:38 PM in C++ Programming

avatar image

erebel55
380 41 44 65

(comments are locked)
10|2000 characters needed characters left

1 answer: sort voted first

I rewrote your code to be correct as it should be easier to understand that way. Logic is as follows:

  • Client performs action

  • Client tells server of action

  • Server validates action and executes server logic for action

  • Server replicates the execution of that action to all other clients

    void AFPSWeapon::StartFire() { // If were a client if (!HasAuthority()) { // Tell the server we want to fire ServerStartFire(); }

       // If were a server
         if (HasAuthority())
         {
             // Get the ability components attached to this weapon
             TArray<UActorComponent*> AbilityComponents = GetComponentsByClass(UFPSAbilityComponent::StaticClass());
             if (AbilityComponents.Num() > 0)
             {
                 // Execute the first ability
                 Cast<UFPSAbilityComponent>(AbilityComponents[0])->ExecuteAbility();
             }
         }
     }
     
     void AFPSWeapon::ServerStartFire_Implementation()
     {
         StartFire()
     }
     
     
     // This should maybe be set to Cond_SkipOwner
     UPROPERTY(Transient, ReplicatedUsing = "OnRep_IsFiring")
     bool IsFiring;
     
     void UFPSAbilityComponent::ExecuteAbility()
     {
         // Double check were on the server
         if (HasAuthority())
         {
             // only do stuff on server
             IsFiring = true;
         }
     }
     
     
     void UFPSAbilityComponent::OnRep_IsFiring()
     {
         // I'm a client told that the server version of this ability just fired
         // So do stuff
     }
     
    
    
    
    
more ▼

answered Feb 01 '16 at 09:46 PM

avatar image

dzeligman
708 32 28 52

avatar image erebel55 Feb 01 '16 at 10:16 PM

This is very helpful, thank you. One caveat that I forgot to mention is that Abilities (UFPSAbilityComponent) can also be attached directly to the character (weaponless-abilities). So that is why I had the server rpc logic within the Ability. In other words, abilities need to be coded so that they can fire without a weapon as well.

avatar image erebel55 Feb 01 '16 at 10:27 PM

Could your approach be shuffled around to support that?

avatar image dzeligman Feb 01 '16 at 10:34 PM

It would still follow the same route:

  • Client (player input) performs action

  • Client tells server of action (player calls server rpc which then on server calls execute on that ability component)

  • Server validates action and executes server logic for action

  • Server replicates the execution of that action to all other clients

As long as the ability component is marked to replicate it can handle exactly the same way. With the weapon case, the weapon component is just an intermediary. If you don't want that logic on the player you could just rename/refactor the weaponcomponent to be like AbilityController and subclass Weapon logic into WeaponAbilityController if there's custom stuff to put there. The AbilityController responds to input and calls the rpcs.

(comments are locked)
10|2000 characters needed characters left
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question