I am writing an ability system and have come to the point where I need to simulate certain things on the client.
Some examples are changing materials, playing particle systems, playing sound effects, etc.
This is an example of something I need to execute on the Client for a cloaking ability.
A quick summary of my ability system design is…
- UAbilityComponent - UActorComponent that exists on the Server and is replicated to Clients. It is attached to a Pawn that can execute abilities. Is the driver of all abilities. In charge of spawning, replicating, and enforcing rules around abilities.
- UAbility - UObject that only exists on the Server (don’t replicate so it is more lightweight). Defines an abilities properties and effects. Does not maintain state.
- FAbilityState - Replicated ability state hosted by UAbilityComponent. Holds the current values of properties that we want to replicate.
I’m am having a hard time figuring out the most lightweight and clean way to implement Ability Simulation.
Normally I would just do something like the following.
// AbilityComponent (ActorComponent)
void AbilityComponent::Multicast_SimulateAbility(int32 ID)
{
Abilities[ID]->SimulateAbility();
}
// Ability (UObject)
UFUNCTION(BlueprintImplementableEvent, Category = Ability)
void SimulateAbility();
void Ability::Execute()
{
AbilityComponent->Multicast_SimulateAbility(ID);
}
That would allow me to override the SimulateAbility function in BP and give me a shell for executing whatever I need to on the client.
However, the issue with that approach is that my UAbility does not exist on the clients (since I want to stay lightweight).
Therefore, I can’t go this route.
Is there some other way to call logic defined on a server only object on the client?
If not, the best way I can think to do this is to create various replicated properties on the UAblityComponent via OnRep.
For example,
- CharacterMaterial
- ParticleSystem
- SoundEffect
- anything else I end up needing
I could then have an OnRep function in UAbilityComponent that actually sets the characters material, plays the particle system, etc.
I would then set these properties from within UAbility to trigger the simulation.
It is a lot less flexible and requires me to keep adding properties to UAbilityComponent.
Can anyone think of anything better?