How to play Weapon Animations? | Getting Error

EDIT: Updated with new infos. Fixed the error, still no animation playing from c++ :frowning:

Hey there,

i have some trouble playing my weapon animations in C++.

I have the Prototype Weapons that come along with a Fire and Reload Animation and i wanted to test my Shooting Methods.
My current system will get the LeftMouseButton press in the PlayerController, check if there is a valid weapon in the weapon
slot and call its ShootWeapon() function:



/// Weapon Functions ///
void ASmallCoopTDPlayerController::ShootWeapon()
{
	ASmallCoopTDCharacter* MyCharacter = Cast<ASmallCoopTDCharacter>(GetPawn());

	if (MyCharacter)
	{
		class ABaseWeaponClass* MyWeapon = Cast<ABaseWeaponClass>(MyCharacter->GetCurrentWeapon());
		if (MyWeapon)
		{
			MyWeapon->ShootWeapon();
		}
	}
}


Now the WeaponClass has 2 Variables to save and set my Animation in the ChildBP (i create the final weapons in as BP, so that
i can edit them easier):



protected:
	/// Weapon Animations ///

	UPROPERTY(Replicated, BlueprintReadWrite, EditDefaultsOnly, Category = "Weapon Animtions")
	UAnimMontage* ReloadAnimation;

	UPROPERTY(Replicated, BlueprintReadWrite, EditDefaultsOnly, Category = "Weapon Animtions")
	UAnimMontage* ShootAnimation;


So these are set in my BP to the specific Animation Montage.
Now in the ShootWeapon() function, i do the following:



/// Client Functions ///

void ABaseWeaponClass::ShootWeapon()
{
	if (Role < ROLE_Authority)
	{
		Server_ShootWeapon();
	}
}

/// Server Functions ///

void ABaseWeaponClass::Server_ShootWeapon_Implementation()
{
	GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, TEXT("Shooting Weapon!"));
	GetWeaponMesh()->GetAnimInstance()->Montage_Play(ShootAnimation);
}

bool ABaseWeaponClass::Server_ShootWeapon_Validate()
{
	return true;
}


The OnScreenMessage is displayed but the Montag Play does nothing.

When i call the same thing withing a blueprint (PlayMontage etc) it is working.
But the same in C++ doesn’t work somehow.

If you need more information or more code, please tell me!

(: Thanks in advance

/// EDIT 1 ///

Ok, i debugged it alot now and it seems like i’m missing some replication here.

If i call this through a normal client side function, it is shooting correctly (not replicated, only visible client side).
If i call it through the server function, it seems like it is playing (Montag_IsPlaying returns true),
but i can’t see the animation ingame.

Could it be that the animation/Matinee states are not replicated, that the client itself is responsible for playing them. What I mean is that since the animation start is in the Server_Shoot_Weapon_Implementation() that is only executed on the server.

I would guess everything that has to do with (view) rendering should need to be handled localy. That the server implementation of shoot weapon do spawning of projectiles or collision logic, but then calls a function avalible for both client and server to actually run the animation. I am not sure. But it sounds like it would produce the error seen.

Thanks for you answer (:

Yes, it seems like i’m missing some replication logic here.

I drew a small setup of what the Server and the Client needs to handle:

http://puu.sh/grzoK/59752b03ec.png

But how to i play the Animation on every Client Copy of that character?
How should i use States if i only work with a single Montage_Play call?

>.< The ShooterGame is way to complicated in that. It sets some bools
and the State of the Weapon, but in the end, it just calls the Montage_Play…

The shootergame sets its own state, which then goes to the server via RPC, which then updates that state to all the other clients. Have a look at how the state replication values are setup for the firing (I think its bIsFiring value, don’t have my code available right now).

So generally, you’d play your animation locally on the client, send an RPC to the server to update, then set a replicated property on the server that replicates it to everyone but the owning client (the one who started firing, because they’ll have done it locally already).

If you’re doing a networked game, you would be well advised to review the replication documentation and look over the shootergame code for usage. Although there seem to be a bunch of gotchas :slight_smile:

I have the ShooterGame Code open all the time. They are calling the FireWeapon() Function IN the SetWeaponState function.
Took me a while to find this, because i wouldn’t have guessed the SetWeaponState function to also look if the newState is “Fire” and
call the FireWeapon() Function.

So they fire the weapon by changing the state to Fire, but the state isn’t replicated. So why does changing this State (on the firing client and on the server)
update the whole Weapon on EVERY client. I thought only replicated variables will be updated through the network to all clients by the server?
Or does changing a nonreplicated variable as the server always change it on the rest of the clients?

The Animation itself is called in “SimulateWeaponFire()” and it only runs on a client (returns if you are a server).

What i don’t really get with these RPC things is:

When do they switch from ONE Client - Server Communication to ALL Clients - Server Communication?

Forget the base class, shooterweapon doesn’t actually matter so much. Take a look at shooterweapon_instant instead.

Here’s how it breaks down:

  • In FireWeapon it calls weapontrace to do the raycast,
  • it then calls ProcessInstantHit.
  • On the client, this then causes a call to ServerNotifyHit or ServerNotifyMiss depending on whether it hit a blocking object or not. It also calls ProcessInstantHit_Confirmed locally to do the effects.
  • The server gets this RPC call (rather unintuitively via ServerNotifyHit_Implementation), does some sanity checking, then calls ProcessInstantHit_Confirmed if the hit is valid.
  • ProcessInstantHit_Confirmed then sets the HitNotify values, which are on the replicated FInstantHitInfo object called HitNotify in the shooterweapon_instant class.
  • Clients handle the change in hitnotify via OnRep_HitNotify

So basically, the client does some effects on the client end, whilst sending an RPC to the server. Server responds by updating the HitNotify structure, which then replicates to all the clients. Clients handle this change in OnRep_HitNotify for spawning their own effects etc.

There’s a bunch of other details in there to be sure. But that’s the main train of how it works. I suspect its a bit harder to follow because of the whole _Implementation and such. Which I believe is going away in 4.7 in favour of the same function names as the declaration, which might well be a good thing. The other part that can be confusing is that the same function often gets called twice. Once for client and once for server. Often if you see checks for Role == Role_Authority, it means “this is the server bit of that code”, usually the client calls it, but has different effects than when the server calls it.

One other thing to look at is in ShooterCharacter, have a look in GetLifetimeReplicatedProps, which sets up the type of replication for the character and might give you some hints about how to setup selective replication.

Hope that helps a bit.

Thanks for that but… i know how replication works. I know what the Roles and functions do, but the ShooterGame Weapon System itself is rather complicated.
Also i asked for the Animation and not for the Hit and Damage, so the ShooterWeapon_Instant is not important at all.

All this happens inside the Base Class and i only want to know how to replicate the Montage_Play to all clients.

ShooterWeapon BurstCounter looks like its the bit responsible for updating the animations. Its replicated (firing calls OnBurstStarted started, which RPC’s to the server via the ServerHandleFiring call in HandleFiring, which updates the BurstCounter variable on the server, which then gets handled by the clients in OnRep_BurstCounter to either keep firing (BurstCounter > 0) or stop firing (Burst == 0)

It calls SimulateWeaponFire/StopSimulatingWeaponFire which in turn calls PlayWeaponAnimation/StopWeaponAnimation which play the montages or not.

The montages aren’t replicated. The burst counter is. A counter of 0 stops animation, a counter of > 0 plays the animation.

Its all pretty much the same cycle of updating. Handle client side state change. RPC that new state to the server. Server sets some value that then is replicated to the clients. Clients handle the replication in a notify and do something with the new value.

So to be clear. Have some variable on your (local) client count up while firing and play the firing animation. RPC that value to the server. On the server, replicate that value to the other clients. On the other (non local) clients check the value and if > 0 play the montage for firing, otherwise stop playing it. The reason to have a counter is I guess to not immediately halt the firing for when firing comes to the server out of order or delayed a little. Essentially acting like a small time window buffer to maintain the firing state.

Ah! That’s the info i needed. I haven’t really noticed the burstCounter. Its name is a bit missleading, but watching the code for it makes it clear now.

A ReplicatedNotify is fired when the matching variable is updated or?
So HandleFiring() updates it on the Client calling it and on the server when it’s called by the server.
When the server does it, it will be replicated to all other clients as well and the Notify is called. This will call
the “SimulateWeaponFire” which plays the Animation on all clients.

Keeping the mousebutton pressed will continue shooting (HandleFire calls itself if refiring is true with a dealy > 0.0f).
Releasing the mouse button sets the counter to 0 (calls the repnotify) and stop all action.

Now it is way more structured in my mind and this setup is pretty cool, although it’s still a bit complicated.
Sometimes it seems like they just split everything up to have it smaller instead of one big function.

Thank you very much!

The replicate notify method if fired when the client receives an update to the variable. Although you have to be a bit careful, because if you’re playing on a localhost server (so youre a client AND a server) the notification never takes place (I guess in that case some combination of Role and authority allow the client side code to handle it anyway.

There’s also the little issue of some RPC’s not being called if the client doesn’t own the actor thats calling the RPC, but in general the replication system just works.

Glad that helped.