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!