Replicating Components on Blueprints

Based on the ShooterGame sample, I created a new weapon (via Blueprint). It’s a weapon that changes its color (among other things, but irrelevant right now) based on whether it’s hit by sunlight or not.

Skipping the details, the functionality is working, but the change is only visible on the local machine (server or client). I want it to be replicated.

So, I have the following setup… here’s the construction script.

Here’s the event graph (only the relevant part):

I tried setting the property “Replication” to “Replicated” on the variables Material1P and Material3P (I know, only really needed on Material3P), but then the change only happens on the server, and not on the client(s). The Timeline also has “Replicated” checked.

I also tried changing the Mesh1P and Mesh3P declaration:

UPROPERTY(BlueprintReadOnly, Replicated, VisibleDefaultsOnly, Category=Mesh)
TSubobjectPtr Mesh3P;

Didn’t help too. Ideas?

Ive made a hability system for Network game, and it works just fine, but in the first version i made, i made the habilities able to be coded in blueprint. it worked fine in singleplayer, but it NEVER worked on multiplayer, the blueprint event was never called in the client.
The habilities are separate actors attached to the character(more or less like the gun in shootergame, but without a mesh), and i call the StartHability function on them, where they do their logic for cooldown and stuff and then call the event Activate. this event calls BPActivate, wich is a blueprintImplementableEvent, and in subclasses i override that to do the logic i need in them. the habilities logic is mostly called in client only ATM, as its the client the one who clicks the hability button. and i found that the blueprint event just didnt even work

Hi, there is a lot going on here!

You are on the right path I think. For something like this, it is best to replicate the state w/ a bool like IsSunLit and handle material swaps in the rep notify. Dynamic materials cannot be replicated in the way you were trying in your original post. You are best to do this all at a higher level and have client side code do the actual material swap.

My question is - who is setting IsSunlit? Ideally the server is in complete control of IsSunLit on everybody’s weapon. When the server sets IsSunlit, it reps down to everyone else and everyone does the material swap. What it sounds like what is happening is you are setting IsSunlit in some code that is being run on the local client machine. IsSunLit will not replicated client → server. If IsSunlit has to be set on the client, then like you suggest in your last post, you need to send a server RPC to the server, telling him to change IsSunlit to the new value. Then all the server does is call Set w/ Notify on IsSunLit and everyone gets the new value and does the material swap. (so, like I said, I think you are close: If ServerSetWeapon3PScalarMaterialInstance is really necessary, then it should just set IsSunlit, and the material change should happen in the RepNotify)

Does that make sense?

To answer your other question - don’t do a RemoteRole < 2 check. You can use the “Switch Has Authority” macro in blueprints for determining if the local machine is the authority (server).

Woot, after a lot of research and attempts and tea cups, we finally got it to work!

So here’s what I did. If I did something wrong or inefficient, let me know. I’m still learning replication. :slight_smile: (just waiting for your feedback to mark as solved)

First, I followed your suggestion and removed the ServerSetWeapon3PScalarMaterialInstance function. The material changes will depend solely on the blueprint boolean, IsSunlit.

I also changed the constructor. Basically, what I wanted is, “if the weapon belongs to me then create Mesh1P’s MID only, otherwise create Mesh3P’s MID only”. Because this check depends on the weapon’s owner pawn being not null, I moved to the event WeaponBeingEquipped. (note: neither Material1P or Material3P is replicated)

On TickActor(), where I check if the weapon is hit by a directional light, I added if (Role == ROLE_Authority) before the check, so the server is the sole responsible for checking that. If the weapon moves to/from sunlight, the BlueprintImplementableEvent IsSunlitChanged() is called.

Now this is the event’s implementation in Blueprint.

First thing it sets IsSunlit, which is defined as RepNotify. The OnRep_IsSunlit function simply changes the 3rd person material.

8.png

Then it changes the projectile class and firing mode. These functions were declared as UFUNCTION(BlueprintCallable, Server, Reliable, Category=Weapon), and the variable they change are also set as Replicated and added to GetReplicationList(). To be honest I don’t really understand this completely, maybe I’m doing something redundant, I’ll experiment with this later.

Lastly, the 1st person material is changed smoothly according to a Timeline. Note: it only worked after I checked “Replicated” on the Timeline.

And that’s it. :slight_smile:

Also as a feedback, the compile in editor feature helped greatly here (as I was experimenting with changing a lot of stuff in TickActor() alone).

Thanks for the help everyone!

This sounds pretty good. I think you could get by without having the timeline replicated if you just set up the timeline in the IsSunLit RepNotify. The logic would be “server told me if the weapon is sunlit or not, change the 3P material and if this is locally controlled, setup a timeline to change the 1P material”.

Yes, makes sense.

But the “Add Timeline” option is not available on functions, apparently it’s only available on the EventGraph.

I copied and pasted from the Event Graph, the timeline just wouldn’t do anything.

I’ll leave this as a request then, if it is possible at all, to have timelines inside blueprint functions.

Thanks Dave!

Ahh yeah, that is correct. We could make OnReps be able to be custom events on the event graph, instead of functions. But that might be confunsing to support both. We will discuss the options here.

It’s a little difficult for me to put together a totally valid answer, because I’m pretty new to UE4 still, but I imagine that replication still works mostly like it always has – in the past, only Actors and their subclasses were directly replicateable to clients. If the component chain still works the same way as it used to, *Component are not Actors, and therefore they do not get replicated and auto-created on the client ends.

From a UE3 perspective, what I would do, is replicate a variable that points to the package blueprint being used for the component, and then when that variable is received on the clients ends, then you know that you need to change out the Mesh components locally.

Not sure if that makes sense. :-S

Hmm, I understand, thanks for your explanation.

So in my case, I guess I could make that boolean “Is Sunlit” (it’s a variable on ShooterWeapon) a RepNotify, then change meshes on the repnotify method.

I’ll try it later tonight when I get home.

Still not working properly… I wonder if this can be done purely on blueprints.

Here my current implementation.

First of all, I realized I was creating material instances for 1st and 3rd person for every for every pawn, which is inefficient, as we don’t need to create a material instance dynamic for the first person material instance on another pawn (another client), as we’ll never see it.

So first thing was to create a Material Instance Dynamic on the first person material only if you’re the owner of the weapon. How to do this however, I’m not sure. I suppose you have to verify RemoteRole, right? What should it be? >2, ==1, etc…? This is my first question.

Ok. Now this may be relevant. The event “Is Sunlit Changed” is verified locally (I think), on the client. Here is the function signature:

	UFUNCTION(BlueprintImplementableEvent, Category=Weapon)
	void IsSunlitChanged(bool IsSunlit);

It is called from TickActor() when the weapon has moved from light to shadow or vice versa.

Now, I have created a boolean on the weapon blueprint, called “IsSunlit”, with replication set to RepNotify. So when the client’s weapon has moved from light/shadow, this variable is set, and the function OnRep_IsSunlit is called.

Here is my current implementation of OnRep_IsSunlit. Basically, I want to create a Material Instance Constant on the Mesh3P of the weapon, and set a scalar parameter.

The end result is that the server pawn’s weapon material is replicated to the clients, but the clients pawn’s weapon materials aren’t replicated between themselves or the server.

On the screenshot, the big screen is the server; the small ones are clients. All weapons should be yellow (yellow = IsSunlit; purple = not IsSunlit).

Second question: any suggestions on how to fix this?

Well, I’m still new to replication and UE4, so I’m kinda lost here.

I added a function:

	/** set 3rd person weapon material instance (scalar) */
	UFUNCTION(BlueprintCallable, Server, Reliable, Category=Weapon)
	void ServerSetWeapon3PScalarMaterialInstance(FName ParameterName, float Value);
	

void AShooterWeapon::ServerSetWeapon3PScalarMaterialInstance_Implementation(FName ParameterName, float Value)
{
	UMaterialInstanceDynamic* MaterialInstance3P = Mesh3P->CreateDynamicMaterialInstance(0);
	MaterialInstance3P->SetScalarParameterValue(ParameterName,Value); 
}

Now the server is receiving the new weapon colors, but it’s not sending the change to clients. How do I tell the server to replicate that?